Denis Chertykov <denisc@overta.ru>
authorDenis Chertykov <denisc@overta.ru>
Fri, 11 Feb 2000 22:31:46 +0000 (14:31 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 11 Feb 2000 22:31:46 +0000 (14:31 -0800)
        * README.AVR: New file with information about the avr ports.
        * config/avr: New directory with avr port files.

From-SVN: r31935

gcc/ChangeLog
gcc/README.AVR [new file with mode: 0644]
gcc/config/avr/avr-protos.h [new file with mode: 0644]
gcc/config/avr/avr.c [new file with mode: 0644]
gcc/config/avr/avr.h [new file with mode: 0644]
gcc/config/avr/avr.md [new file with mode: 0644]
gcc/config/avr/libgcc.S [new file with mode: 0644]
gcc/config/avr/t-avr [new file with mode: 0644]
gcc/config/avr/xm-avr.h [new file with mode: 0644]

index 01cb80f..1632ef2 100644 (file)
@@ -1,3 +1,8 @@
+2000-02-11  Denis Chertykov  <denisc@overta.ru>
+
+       * README.AVR: New file with information about the avr ports.
+       * config/avr: New directory with avr port files.
+
 2000-02-11  Andreas Jaeger  <aj@suse.de>
 
        * fixinc/Makefile.in (FIXINC_DEFS): Remove unneeded @fixinc_defs@.
@@ -335,17 +340,17 @@ Thu Feb 10 18:28:59 MET 2000  Jan Hubicka  <jh@suse.cz>
 
 2000-02-09  Scott Bambrough  <scottb@netwinder.org>
 
-        * config/arm/arm.md (movsi): In PIC mode, make sure that a
-        constant source address is legitimate.
+       * config/arm/arm.md (movsi): In PIC mode, make sure that a
+       constant source address is legitimate.
 
 2000-02-09  Philip Blundell  <pb@futuretv.com>
 
-        * config/arm/arm.c (legitimize_pic_address): Handle LABEL_REF
-        correctly.
+       * config/arm/arm.c (legitimize_pic_address): Handle LABEL_REF
+       correctly.
 
-        * config/arm/arm.h (LEGITIMATE_CONSTANT_P): Allow anything when
-        generating PIC.
-        (LEGITIMATE_PIC_OPERAND): Disallow references to labels.
+       * config/arm/arm.h (LEGITIMATE_CONSTANT_P): Allow anything when
+       generating PIC.
+       (LEGITIMATE_PIC_OPERAND): Disallow references to labels.
 
 2000-02-09  Zack Weinberg  <zack@wolery.cumb.org>
 
@@ -396,8 +401,8 @@ Tue Feb  8 15:51:50 2000  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
 
 2000-02-08  Clinton Popetz  <cpopetz@cygnus.com>
 
-        * function.c (thread_prologue_and_epilogue_insns): Don't replace
-        jumps with returns unless they are jumps to the fallthru block.
+       * function.c (thread_prologue_and_epilogue_insns): Don't replace
+       jumps with returns unless they are jumps to the fallthru block.
 
 Tue Feb  8 07:53:55 2000  Jan Hubicka  <jh@suse.cz>
 
diff --git a/gcc/README.AVR b/gcc/README.AVR
new file mode 100644 (file)
index 0000000..0971cec
--- /dev/null
@@ -0,0 +1,23 @@
+This file describes the implementation notes of the GNU C Compiler for
+the ATMEL AVR micro controllers family.
+
+The generated assembly code requires the GNU assembler (GAS).  This is
+not currently included as part of the binutils package.
+Patches against binutils-2.9.5.0.13 can be obtained from
+http://medo.fov.uni-mb.si/mapp/uTools.  This site also has patches for
+the GNU debugger (GDB).
+
+
+GCC can be configured as a cross compiler for the AVR architectures
+on the same system.  Use `configure --target=avr' to configure GCC.
+
+
+Further installation notes and other useful information about AVR tools
+can also be obtained from http://medo.fov.uni-mb.si/mapp/uTools.
+
+
+Mailing list, avr@fov.uni-mb.si, exists to discuss related issues and
+suggestions for further optimizations and improvements.
+
+
+Denis Chertykov <denisc@overta.ru>,  30 Jan 2000
\ No newline at end of file
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
new file mode 100644 (file)
index 0000000..fc525c2
--- /dev/null
@@ -0,0 +1,152 @@
+/* Prototypes for exported functions defined in avr.c
+   
+   Copyright (C) 2000 Free Software Foundation, Inc.
+   Contributed by Denis Chertykov (denisc@overta.ru)
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+
+extern void   avr_output_ascii                  PARAMS ((FILE *file,
+                                                       const char *p,
+                                                       int size));
+extern int    function_arg_regno_p              PARAMS ((int r));
+extern void   asm_file_start                    PARAMS ((FILE *file));
+extern void   asm_file_end                      PARAMS ((FILE *file));
+extern void   avr_init_once                     PARAMS ((void));
+extern void   avr_override_options              PARAMS ((void));
+extern char * avr_change_section                PARAMS ((char *sect_name));
+extern int    avr_ret_register                  PARAMS((void));
+extern enum reg_class class_likely_spilled_p    PARAMS ((int c));
+extern enum reg_class avr_regno_reg_class       PARAMS ((int r));
+extern enum reg_class avr_reg_class_from_letter PARAMS ((int c));
+extern int    frame_pointer_required_p          PARAMS ((void));
+extern void   asm_globalize_label               PARAMS ((FILE *file,
+                                                       const char *name));
+extern void   order_regs_for_local_alloc        PARAMS ((void));
+extern int    initial_elimination_offset        PARAMS ((int from, int to));
+extern void   function_prologue                 PARAMS ((FILE *file, int size));
+extern void   function_epilogue                 PARAMS ((FILE *file, int size));
+extern void   progmem_section                   PARAMS ((void));
+extern int    mask_one_bit_p                    PARAMS ((HOST_WIDE_INT mask));
+
+#ifdef TREE_CODE
+extern void   asm_output_external          PARAMS ((FILE *file, tree decl,
+                                                  char *name));
+extern void   unique_section               PARAMS ((tree decl, int reloc));
+extern void   encode_section_info          PARAMS ((tree decl));
+extern void   asm_output_section_name      PARAMS ((FILE *file, tree decl,
+                                                  const char *name,
+                                                  int reloc));
+extern int    valid_machine_type_attribute PARAMS ((tree type, tree attributes,
+                                                  tree identifier,
+                                                  tree args));
+extern int    valid_machine_decl_attribute PARAMS ((tree decl, tree attributes,
+                                                  tree attr, tree args));
+
+#ifdef RTX_CODE /* inside TREE_CODE */
+extern rtx    avr_function_value           PARAMS ((tree type, tree func));
+extern void   init_cumulative_args         PARAMS ((CUMULATIVE_ARGS *cum,
+                                                  tree fntype, rtx libname,
+                                                  int indirect));
+extern rtx    function_arg         PARAMS ((CUMULATIVE_ARGS *cum,
+                                          enum machine_mode mode,
+                                          tree type, int named));
+
+
+#endif /* RTX_CODE inside TREE_CODE */
+
+#ifdef HAVE_MACHINE_MODES /* inside TREE_CODE */
+extern void   function_arg_advance PARAMS ((CUMULATIVE_ARGS *cum,
+                                          enum machine_mode mode, tree type,
+                                          int named));
+#endif /* HAVE_MACHINE_MODES inside TREE_CODE*/
+#endif /* TREE_CODE */
+
+#ifdef RTX_CODE
+extern void   asm_output_external_libcall PARAMS ((FILE *file, rtx symref));
+extern int    legitimate_address_p    PARAMS ((enum machine_mode mode, rtx x,
+                                       int strict));
+extern void   machine_dependent_reorg PARAMS ((rtx first_insn));
+extern int    compare_diff_p  PARAMS ((rtx insn));
+extern char * out_movqi_r_mr  PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movqi_mr_r  PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movhi_r_mr  PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movhi_mr_r  PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movsi_r_mr  PARAMS ((rtx insn, rtx op[], int *l));
+extern char * out_movsi_mr_r  PARAMS ((rtx insn, rtx op[], int *l));
+extern char * output_movsisf  PARAMS ((rtx insn, rtx operands[],
+                                     int which_alternative));
+extern char * out_tstsi       PARAMS ((rtx insn, int *l));
+extern char * out_tsthi       PARAMS ((rtx insn, int *l));
+extern char * ret_cond_branch PARAMS ((RTX_CODE cond, int len));
+
+extern char * ashlqi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashlhi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashlsi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+
+extern char * ashrqi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashrhi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * ashrsi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+
+extern char * lshrqi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * lshrhi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+extern char * lshrsi3_out     PARAMS ((rtx insn, rtx operands[], int *len));
+
+extern int    avr_address_cost       PARAMS ((rtx x));
+extern enum reg_class preferred_reload_class PARAMS ((rtx x,
+                                                    enum reg_class class));
+extern int    extra_constraint       PARAMS ((rtx x, char c));
+extern rtx    legitimize_address     PARAMS ((rtx x, rtx oldx,
+                                            enum machine_mode mode));
+extern int    adjust_insn_length     PARAMS ((rtx insn, int len));
+extern rtx    avr_libcall_value      PARAMS ((enum machine_mode mode));
+extern char * output_reload_inhi     PARAMS ((rtx insn, rtx *operands,
+                                            int which_alternative));
+extern char * output_reload_insisf   PARAMS ((rtx insn, rtx *operands,
+                                            int which_alternative));
+extern int    default_rtx_costs      PARAMS ((rtx X, RTX_CODE code,
+                                            RTX_CODE outer_code));
+extern void   asm_output_char        PARAMS ((FILE *file, rtx value));
+extern void   asm_output_short       PARAMS ((FILE *file, rtx value));
+extern void   asm_output_byte        PARAMS ((FILE *file, char value));
+extern enum reg_class secondary_input_reload_class PARAMS ((enum reg_class,
+                                                          enum machine_mode,
+                                                          rtx));
+extern void   notice_update_cc       PARAMS ((rtx body, rtx insn));
+extern void   print_operand          PARAMS ((FILE *file, rtx x, int code));
+extern void   print_operand_address  PARAMS ((FILE *file, rtx addr));
+extern int    reg_unused_after       PARAMS ((rtx insn, rtx reg));
+extern int    _reg_unused_after      PARAMS ((rtx insn, rtx reg));
+extern int    avr_jump_mode          PARAMS ((rtx x, rtx insn));
+extern int    byte_immediate_operand PARAMS ((register rtx op,
+                                            enum machine_mode mode));
+
+#endif /* RTX_CODE */
+
+#ifdef HAVE_MACHINE_MODES
+extern int    class_max_nregs        PARAMS ((enum reg_class class,
+                                            enum machine_mode mode));
+#endif /* HAVE_MACHINE_MODES */
+
+#ifdef REAL_VALUE_TYPE
+
+extern void   asm_output_float       PARAMS ((FILE *file, REAL_VALUE_TYPE n));
+
+#endif 
+
+
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
new file mode 100644 (file)
index 0000000..21c87dc
--- /dev/null
@@ -0,0 +1,3750 @@
+/* Subroutines for insn-output.c for ATMEL AVR micro controllers
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Denis Chertykov (denisc@overta.ru)
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+   
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "reload.h"
+#include "tree.h"
+#include "expr.h"
+#include "toplev.h"
+#include "obstack.h"
+#include "function.h"
+#include "recog.h"
+#include "tm_p.h"
+
+
+static int    avr_naked_function_p PARAMS ((tree));
+static int    interrupt_function_p PARAMS ((tree));
+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));
+
+
+/* Allocate registers from r25 to r8 for parameters for function calls */
+#define FIRST_CUM_REG 26
+
+/* Temporary register RTX (gen_rtx (REG,QImode,TMP_REGNO)) */
+rtx tmp_reg_rtx;
+
+/* Zeroed register RTX (gen_rtx (REG,QImode,ZERO_REGNO)) */
+rtx zero_reg_rtx;
+
+/* AVR register names {"r0", "r1", ..., "r31"} */
+char * avr_regnames[] = REGISTER_NAMES;
+
+/* This holds the last insn address.  */
+static int last_insn_address = 0;
+
+/* Commands count in the compiled file */
+static int commands_in_file;
+
+/* Commands in the functions prologues in the compiled file */
+static int commands_in_prologues;
+
+/* Commands in the functions epilogues in the compiled file */
+static int commands_in_epilogues;
+
+/* Prologue/Epilogue size in words */
+static int prologue_size;
+static int epilogue_size;
+
+/* Initial stack value specified by the `-minit-stack=' option */
+const char *avr_ram_end = NULL;
+
+/* Numeric representation */
+static const char *initial_stack;
+
+/* Default MCU name */
+const char *avr_mcu_name = "at90s8515";
+
+/* Default MCU */
+struct mcu_type_s *avr_mcu_type;
+
+/* MCU names, initial stack value, flag 'mega' */
+static struct mcu_type_s mcu_types[] =
+{{"at90s2313", 224-1, 0},
+ {"at90s2323", 224-1, 0},
+ {"at90s2333", 224-1, 0},
+ {"attiny22",  224-1, 0},
+ {"at90s2343", 224-1, 0},
+ {"at90s4433", 224-1, 0},
+ {"at90s4414", 0x15f, 0},
+ {"at90s4434", 0x15f, 0},
+ {"at90s8515", 0x25f, 0},
+ {"at90s8535", 0x25f, 0},
+ {"atmega603", 0x0fff,1},
+ {"atmega103", 0x0fff,1},
+ {NULL,0,0}};
+
+/* Setup MCU */
+
+void
+avr_override_options (void)
+{
+  for (avr_mcu_type = mcu_types; avr_mcu_type->name; ++avr_mcu_type)
+    if (strcmp (avr_mcu_type->name, avr_mcu_name) == 0)
+      break;
+  if (!avr_mcu_type->name)
+    {
+      int i;
+      fprintf (stderr,
+              "Wrong mcu `%s' specified\n"
+              "Allowed mcu's:\n", avr_mcu_name);
+      for (i = 0; mcu_types[i].name; ++i)
+       fprintf (stderr,"   %s\n", mcu_types[i].name);
+      fatal ("select right mcu name");
+    }
+}
+
+/* Initialize TMP_REG_RTX and ZERO_REG_RTX */
+void
+avr_init_once (void)
+{
+  tmp_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+  memset (tmp_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+  PUT_CODE (tmp_reg_rtx, REG);
+  PUT_MODE (tmp_reg_rtx, QImode);
+  XINT (tmp_reg_rtx, 0) = TMP_REGNO;
+
+  zero_reg_rtx = xmalloc (sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+  memset (zero_reg_rtx, 0, sizeof (struct rtx_def) + 1 * sizeof (rtunion));
+  PUT_CODE (zero_reg_rtx, REG);
+  PUT_MODE (zero_reg_rtx, QImode);
+  XINT (zero_reg_rtx, 0) = ZERO_REGNO;
+}
+
+/*  return register class from register number */
+
+static int reg_class_tab[]={
+  GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
+  GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
+  GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,GENERAL_REGS,
+  GENERAL_REGS, /* r0 - r15 */
+  LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,
+  LD_REGS,                      /* r16 - 23 */
+  ADDW_REGS,ADDW_REGS,          /* r24,r25 */
+  POINTER_X_REGS,POINTER_X_REGS, /* r26,27 */
+  POINTER_Y_REGS,POINTER_Y_REGS, /* r28,r29 */
+  POINTER_Z_REGS,POINTER_Z_REGS, /* r30,r31 */
+  STACK_REG,STACK_REG           /* SPL,SPH */
+};
+
+/* Return register class for register R */
+
+enum reg_class
+avr_regno_reg_class (r)
+     int r;
+{
+  if (r <= 33)
+    return reg_class_tab[r];
+  return ALL_REGS;
+}
+
+
+/* A C expression which defines the machine-dependent operand
+   constraint letters for register classes.  If C is such a
+   letter, the value should be the register class corresponding to
+   it.  Otherwise, the value should be `NO_REGS'.  The register
+   letter `r', corresponding to class `GENERAL_REGS', will not be
+   passed to this macro; you do not need to handle it.  */
+
+enum reg_class
+avr_reg_class_from_letter  (c)
+     int c;
+{
+  switch (c)
+    {
+    case 't' : return R0_REG;
+    case 'b' : return BASE_POINTER_REGS;
+    case 'e' : return POINTER_REGS;
+    case 'w' : return ADDW_REGS;
+    case 'd' : return LD_REGS;
+    case 'l' : return NO_LD_REGS;
+    case 'a' : return SIMPLE_LD_REGS;
+    case 'x' : return POINTER_X_REGS;
+    case 'y' : return POINTER_Y_REGS;
+    case 'z' : return POINTER_Z_REGS;
+    case 'q' : return STACK_REG;
+    default: break;
+    }
+  return NO_REGS;
+}
+
+/* Return non-zero if FUNC is a naked function.  */
+
+static int
+avr_naked_function_p (func)
+     tree func;
+{
+  tree a;
+
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    abort ();
+  
+  a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
+  return a != NULL_TREE;
+}
+
+/* Return nonzero if FUNC is an interrupt function as specified
+   by the "interrupt" attribute.  */
+
+static int
+interrupt_function_p (func)
+     tree func;
+{
+  tree a;
+
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    return 0;
+
+  a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+  return a != NULL_TREE;
+}
+
+/* Return nonzero if FUNC is an signal function as specified
+   by the "signal" attribute.  */
+
+static int
+signal_function_p (func)
+     tree func;
+{
+  tree a;
+
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    return 0;
+
+  a = lookup_attribute ("signal", DECL_MACHINE_ATTRIBUTES (func));
+  return a != NULL_TREE;
+}
+
+/* Compute offset between arg_pointer and frame_pointer */
+
+int
+initial_elimination_offset (from,to)
+     int from ATTRIBUTE_UNUSED;
+     int to ATTRIBUTE_UNUSED;
+{
+  int reg;
+  int interrupt_func_p = interrupt_function_p (current_function_decl);
+  int signal_func_p = signal_function_p (current_function_decl);
+  int leaf_func_p = leaf_function_p ();
+  int offset= frame_pointer_needed ? 2 : 0;
+
+  for (reg = 0; reg < 32; ++reg)
+    {
+      if ((!leaf_func_p && (call_used_regs[reg]
+                           && (interrupt_func_p || signal_func_p)))
+         || (regs_ever_live[reg]
+             && (!call_used_regs[reg] || interrupt_func_p || signal_func_p)
+             && ! (frame_pointer_needed
+                   && (reg == REG_Y || reg == (REG_Y+1)))))
+       {
+         ++offset;
+       }
+    }
+  return get_frame_size () + 2 + 1 + offset;
+}
+
+/* This function checks sequence of live registers */
+
+static int
+sequent_regs_live ()
+{
+  int reg;
+  int live_seq=0;
+  int cur_seq=0;
+
+  for (reg = 0; reg < 18; ++reg)
+    {
+      if (!call_used_regs[reg])
+       {
+         if (regs_ever_live[reg])
+           {
+             ++live_seq;
+             ++cur_seq;
+           }
+         else
+           cur_seq = 0;
+       }
+    }
+
+  if (!frame_pointer_needed)
+    {
+      if (regs_ever_live[REG_Y])
+       {
+         ++live_seq;
+         ++cur_seq;
+       }
+      else
+       cur_seq = 0;
+
+      if (regs_ever_live[REG_Y+1])
+       {
+         ++live_seq;
+         ++cur_seq;
+       }
+      else
+       cur_seq = 0;
+    }
+  else
+    {
+      cur_seq += 2;
+      live_seq += 2;
+    }
+  return (cur_seq == live_seq) ? live_seq : 0;
+}
+
+
+/* Output function prologue */
+
+void
+function_prologue (FILE *file, int size)
+{
+  int reg;
+  int interrupt_func_p;
+  int signal_func_p;
+  int leaf_func_p;
+  int main_p;
+  int live_seq;
+  int minimize;
+  
+  if (avr_naked_function_p (current_function_decl))
+    {
+      fprintf (file, "/* prologue: naked */\n");
+      return;
+    }
+
+  interrupt_func_p = interrupt_function_p (current_function_decl);
+  signal_func_p = signal_function_p (current_function_decl);
+  leaf_func_p = leaf_function_p ();
+  main_p = ! strcmp ("main", current_function_name);
+  live_seq = sequent_regs_live ();
+  minimize = (TARGET_CALL_PROLOGUES
+             && !interrupt_func_p && !signal_func_p && live_seq);
+
+  last_insn_address = 0;
+  prologue_size = 0;
+  fprintf (file, "/* prologue: frame size=%d */\n", size);
+  
+  if (interrupt_func_p)
+    {
+      fprintf (file,"\tsei\n");
+      ++prologue_size;
+    }
+  if (interrupt_func_p | signal_func_p)
+    {
+      fprintf (file, "\t"
+               AS1 (push,__zero_reg__)   CR_TAB
+               AS1 (push,__tmp_reg__)    CR_TAB
+              AS2 (in,__tmp_reg__,__SREG__) CR_TAB
+              AS1 (push,__tmp_reg__)    CR_TAB
+              AS1 (clr,__zero_reg__)    "\n");
+      prologue_size += 5;
+    }
+  if (main_p)
+    {
+      fprintf (file, ("\t" 
+                     AS2 (ldi, r28, lo8(%s - %d)) CR_TAB
+                     AS2 (ldi, r29, hi8(%s - %d)) CR_TAB
+                     AS2 (out,__SP_L__,r28)       CR_TAB
+                     AS2 (out,__SP_H__,r29) "\n"),
+              initial_stack, size, initial_stack, size);
+      
+      prologue_size += 4;
+    }
+  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);
+
+      fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB
+                     AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB)
+              ,current_function_name, current_function_name);
+      
+      prologue_size += 4;
+      
+      if (AVR_MEGA)
+       {
+         fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
+                  (18 - live_seq) * 2);
+         prologue_size += 2;
+       }
+      else
+       {
+         fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
+                  (18 - live_seq) * 2);
+         ++prologue_size;
+       }
+      fprintf (file, ".L_%s_body:\n", current_function_name);
+    }
+  else
+    {
+      for (reg = 0; reg < 32; ++reg)
+       {
+         if ((!leaf_func_p
+              && (call_used_regs[reg]
+                  && (interrupt_func_p || signal_func_p)
+                  && !(reg == TMP_REGNO || reg == ZERO_REGNO)))
+             || (regs_ever_live[reg]
+                 && (!call_used_regs[reg]
+                     || interrupt_func_p || signal_func_p)
+                 && ! (frame_pointer_needed
+                       && (reg == REG_Y || reg == (REG_Y+1)))))
+           {
+             fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
+             ++prologue_size;
+           }
+       }
+      if (frame_pointer_needed)
+       {
+         {
+           fprintf (file, "\t"
+                    AS1 (push,r28) CR_TAB
+                    AS1 (push,r29) CR_TAB
+                    AS2 (in,r28,__SP_L__) CR_TAB
+                    AS2 (in,r29,__SP_H__) "\n");
+           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;
+                 }
+               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;
+                 }
+               else if (signal_func_p || TARGET_NO_INTERRUPTS)
+                 {
+                   fprintf (file,
+                            AS2 (out,__SP_L__,r28) CR_TAB
+                            AS2 (out,__SP_H__,r29) "\n");
+                   prologue_size += 2;
+                 }
+               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;
+                 }
+             }
+         }
+       }
+    }
+  fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
+}
+
+/* Output function epilogue */
+
+void
+function_epilogue (FILE *file, int size)
+{
+  int reg;
+  int interrupt_func_p;
+  int signal_func_p;
+  int leaf_func_p;
+  int main_p;
+  int function_size;
+  int live_seq;
+  int minimize;
+
+  if (avr_naked_function_p (current_function_decl))
+    {
+      fprintf (file, "/* epilogue: naked */\n");
+      return;
+    }
+
+  interrupt_func_p = interrupt_function_p (current_function_decl);
+  signal_func_p = signal_function_p (current_function_decl);
+  leaf_func_p = leaf_function_p ();
+  main_p = ! strcmp ("main", current_function_name);
+  function_size = (insn_addresses[INSN_UID (get_last_insn ())]
+                  - insn_addresses[INSN_UID (get_insns ())]);
+  live_seq = sequent_regs_live ();
+  minimize = (TARGET_CALL_PROLOGUES
+             && !interrupt_func_p && !signal_func_p && live_seq);
+  
+  epilogue_size = 0;
+  fprintf (file, "/* epilogue: frame size=%d */\n", size);
+  if (main_p)
+    {
+      fprintf (file, "__stop_progIi__:\n\trjmp __stop_progIi__\n");
+      ++epilogue_size;
+    }
+  else if (minimize && (frame_pointer_needed || live_seq > 4))
+    {
+      fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
+      ++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;
+               }
+           }
+       }
+      else
+       {
+         fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
+                         AS2 (in , r29, __SP_H__) CR_TAB));
+         epilogue_size += 2;
+       }
+      
+      if (AVR_MEGA)
+       {
+         fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
+                  (18 - live_seq) * 2);
+         epilogue_size += 2;
+       }
+      else
+       {
+         fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
+                  (18 - live_seq) * 2);
+         ++epilogue_size;
+       }
+    }
+  else
+    {
+      if (frame_pointer_needed)
+       {
+         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;
+               }
+             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;
+               }
+             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;
+               }
+           }
+         fprintf (file, "\t"
+                  AS1 (pop,r29) CR_TAB
+                  AS1 (pop,r28) "\n");
+         epilogue_size += 2;
+       }
+
+      for (reg = 31; reg >= 0; --reg)
+       {
+         if ((!leaf_func_p
+              && (call_used_regs[reg]
+                  && (interrupt_func_p || signal_func_p)
+                  && !(reg == TMP_REGNO || reg == ZERO_REGNO)))
+             || (regs_ever_live[reg]
+                 && (!call_used_regs[reg]
+                     || interrupt_func_p || signal_func_p)
+                 && ! (frame_pointer_needed
+                       && (reg == REG_Y || reg == (REG_Y+1)))))
+           {
+             fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
+             ++epilogue_size;
+           }
+       }
+      
+      if (interrupt_func_p | signal_func_p)
+       {
+         fprintf (file, "\t"
+                  AS1 (pop,__tmp_reg__)      CR_TAB
+                  AS2 (out,__SREG__,__tmp_reg__) CR_TAB
+                  AS1 (pop,__tmp_reg__)      CR_TAB
+                  AS1 (pop,__zero_reg__)     "\n");
+         epilogue_size += 4;
+         fprintf (file, "\treti\n");
+       }
+      else
+       fprintf (file, "\tret\n");
+      ++epilogue_size;
+    }
+  
+  fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
+  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name,
+          prologue_size + function_size + epilogue_size, function_size);
+  commands_in_file += prologue_size + function_size + epilogue_size;
+  commands_in_prologues += prologue_size;
+  commands_in_epilogues += epilogue_size;
+}
+
+
+/* Return nonzero if X (an RTX) is a legitimate memory address on the target
+   machine for a memory operand of mode MODE.  */
+
+int
+legitimate_address_p (mode, x, strict)
+     enum machine_mode mode;
+     rtx x;
+     int strict;
+{
+  int r = 0;
+  if (TARGET_ALL_DEBUG)
+    {
+      fprintf (stderr, "mode: (%s) %s %s %s %s:",
+              GET_MODE_NAME(mode),
+              strict ? "(strict)": "",
+              reload_completed ? "(reload_completed)": "",
+              reload_in_progress ? "(reload_in_progress)": "",
+              reg_renumber ? "(reg_renumber)" : "");
+      if (GET_CODE (x) == PLUS
+         && REG_P (XEXP (x, 0))
+         && GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) >= 0
+         && INTVAL (XEXP (x, 1)) <= (64 - GET_MODE_SIZE (mode))
+         && reg_renumber
+         )
+       fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
+                true_regnum (XEXP (x, 0)));
+      debug_rtx (x);
+    }
+  if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
+                    : REG_OK_FOR_BASE_NOSTRICT_P (x)))
+    r = 'R';
+  else if (CONSTANT_ADDRESS_P (x))
+    r = 'S';
+  else if (GET_CODE (x) == PLUS
+           && REG_P (XEXP (x, 0))
+          && GET_CODE (XEXP (x, 1)) == CONST_INT
+          && INTVAL (XEXP (x, 1)) >= 0)
+    {
+      int fit = INTVAL (XEXP (x, 1)) <= (64 - GET_MODE_SIZE (mode));
+      if (fit)
+       {
+         if (! strict
+             || REGNO (XEXP (x,0)) == REG_Y || REGNO (XEXP (x,0)) == REG_Z)
+             r = 'Q';
+         if (XEXP (x,0) == frame_pointer_rtx
+             || XEXP (x,0) == arg_pointer_rtx)
+           r = 'Q';
+       }
+      else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
+       r = 'U';
+    }
+  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';
+    }
+  if (TARGET_ALL_DEBUG)
+    {
+      fprintf (stderr, "   ret = %c\n", r);
+    }
+  return r;
+}
+
+/* Attempts to replace X with a valid
+   memory address for an operand of mode MODE  */
+
+rtx
+legitimize_address (x, oldx, mode)
+     rtx x;
+     rtx oldx;
+     enum machine_mode mode;
+{
+  x = oldx;
+  if (TARGET_ALL_DEBUG)
+    {
+      fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode));
+      debug_rtx (oldx);
+    }
+  
+  if (GET_CODE (oldx) == PLUS
+      && REG_P (XEXP (oldx,0)))
+    {
+      if (REG_P (XEXP (oldx,1)))
+       x = force_reg (GET_MODE (oldx), oldx);
+      else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT)
+       {
+         int offs = INTVAL (XEXP (oldx,1));
+         if (frame_pointer_rtx != XEXP (oldx,0))
+           if (offs > 64 - GET_MODE_SIZE (mode))
+             {
+               if (TARGET_ALL_DEBUG)
+                 fprintf (stderr, "force_reg (big offset)\n");
+               x = force_reg (GET_MODE (oldx), oldx);
+             }
+       }
+    }
+  return x;
+}
+
+
+/* Return a pointer register name as a string */
+
+static char *
+ptrreg_to_str (regno)
+     int regno;
+{
+  switch (regno)
+    {
+    case REG_X: return "X";
+    case REG_Y: return "Y";
+    case REG_Z: return "Z";
+    default:
+      fatal ("register r%d isn't a pointer\n", regno);
+    }
+  return NULL;
+}
+
+/* Return the condition name as a string.
+   Used in conditional jump constructing  */
+
+static char *
+cond_string (code)
+     enum rtx_code code;
+{
+  switch (code)
+    {
+    case NE:
+      return "ne";
+    case EQ:
+      return "eq";
+    case GE:
+      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
+       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";
+      else
+       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:
+      abort ();
+    }
+}
+
+/* Output ADDR to FILE as address */
+
+void
+print_operand_address (file, addr)
+     FILE *file;
+     rtx addr;
+{
+  switch (GET_CODE (addr))
+    {
+    case REG:
+      fprintf (file, ptrreg_to_str (REGNO (addr)));
+      break;
+
+    case PRE_DEC:
+      fprintf (file, "-%s", ptrreg_to_str (REGNO (XEXP (addr, 0))));
+      break;
+
+    case POST_INC:
+      fprintf (file, "%s+", ptrreg_to_str (REGNO (XEXP (addr, 0))));
+      break;
+
+    default:
+      if (CONSTANT_ADDRESS_P (addr)
+         && (SYMBOL_REF_FLAG (addr) || GET_CODE (addr) == LABEL_REF))
+       {
+         fprintf (file, "pm(");
+         output_addr_const (file,addr);
+         fprintf (file ,")");
+       }
+      else
+       output_addr_const (file, addr);
+    }
+}
+
+
+/* Output X as assembler operand to file FILE */
+     
+void
+print_operand (file, x, code)
+     FILE *file;
+     rtx x;
+     int code;
+{
+  int abcd = 0;
+
+  if (code >= 'A' && code <= 'D')
+    abcd = code - 'A';
+
+  if (REG_P (x))
+    {
+      if (x == zero_reg_rtx)
+       fprintf (file,"__zero_reg__");
+      else
+       fprintf (file, reg_names[true_regnum (x) + abcd]);
+    }
+  else if (GET_CODE (x) == CONST_INT)
+    fprintf (file, "%d", INTVAL (x) + abcd);
+  else if (GET_CODE (x) == MEM)
+    {
+      rtx addr = XEXP (x,0);
+      if (code == 'K')
+       {
+         if (CONSTANT_P (addr))
+           putc ('s', file);
+         else if (GET_CODE (addr) == PLUS)
+           putc ('d', file);
+       }
+      else if (CONSTANT_P (addr) && abcd)
+       {
+         fputc ('(', file);
+         output_address (addr);
+         fprintf (file, ")+%d", abcd);
+       }
+      else if (GET_CODE (addr) == PLUS)
+       {
+         print_operand_address (file, XEXP (addr,0));
+         if (REGNO (XEXP (addr, 0)) == REG_X)
+           fatal_insn ("Internal compiler bug.\nBad address:"
+                       ,addr);
+         fputc ('+', file);
+         print_operand (file, XEXP (addr,1), code);
+       }
+      else
+       print_operand_address (file, addr);
+    }
+  else if (GET_CODE (x) == CONST_DOUBLE)
+    {
+      long val;
+      REAL_VALUE_TYPE rv;
+      if (GET_MODE (x) != SFmode)
+       fatal_insn ("Internal compiler bug. Unknown mode:", x);
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+      REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+      asm_fprintf (file, "0x%x", val);
+    }
+  else if (code == 'j')
+    asm_fprintf (file, cond_string (GET_CODE (x)));
+  else if (code == 'k')
+    asm_fprintf (file, cond_string (reverse_condition (GET_CODE (x))));
+  else
+    output_addr_const (file, x);
+}
+
+/* Recognise operand OP of mode MODE used in call instructions */
+
+int
+call_insn_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) == MEM)
+    {
+      rtx inside = XEXP (op, 0);
+      if (register_operand (inside, Pmode))
+        return 1;
+      if (CONSTANT_ADDRESS_P (inside))
+        return 1;
+    }
+  return 0;
+}
+
+/* Update the condition code in the INSN.  */
+
+void
+notice_update_cc (body, insn)
+     rtx body ATTRIBUTE_UNUSED;
+     rtx insn;
+{
+  switch (get_attr_cc (insn))
+    {
+    case CC_NONE:
+      /* Insn does not affect CC at all.  */
+      break;
+
+    case CC_SET_N:
+      CC_STATUS_INIT;
+      break;
+
+    case CC_SET_ZN:
+      {
+       rtx set = single_set (insn);
+       CC_STATUS_INIT;
+       if (set)
+         {
+           cc_status.flags |= CC_NO_OVERFLOW;
+           cc_status.value1 = SET_DEST (set);
+         }
+      }
+      break;
+
+    case CC_SET_CZN:
+      /* Insn sets the Z,N,C flags of CC to recog_operand[0].
+         The V flag may or may not be known but that's ok because
+         alter_cond will change tests to use EQ/NE.  */
+      {
+       rtx set = single_set (insn);
+       CC_STATUS_INIT;
+       if (set)
+         {
+           cc_status.value1 = SET_DEST (set);
+           cc_status.flags |= CC_OVERFLOW_UNUSABLE;
+         }
+      }
+      break;
+
+    case CC_COMPARE:
+      {
+       rtx set = single_set (insn);
+       CC_STATUS_INIT;
+       if (set)
+         cc_status.value1 = SET_SRC (set);
+      }
+      break;
+
+    case CC_CLOBBER:
+      /* Insn doesn't leave CC in a usable state.  */
+      CC_STATUS_INIT;
+      break;
+    }
+}
+
+/* Return maximum number of consecutive registers of
+   class CLASS needed to hold a value of mode MODE.  */
+
+int
+class_max_nregs (class, mode)
+     enum reg_class class ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
+{
+  return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
+}
+
+/* Choose mode for jump insn:
+   1 - relative jump in range -63 <= x <= 62 ;
+   2 - relative jump in range -2046 <= x <= 2045 ;
+   3 - absolute jump (only for ATmega[16]03).  */
+
+int
+avr_jump_mode (x,insn)
+     rtx x;                     /* jump operand */
+     rtx insn;                  /* jump insn */
+{
+  int dest_addr = insn_addresses[INSN_UID (GET_MODE (x) == LABEL_REF
+                                           ? XEXP (x, 0) : x)];
+  int cur_addr = insn_addresses[INSN_UID (insn)];
+  int jump_distance = cur_addr - dest_addr;
+  
+  if (-63 <= jump_distance && jump_distance <= 62)
+    return 1;
+  else if (-2046 <= jump_distance && jump_distance <= 2045)
+    return 2;
+  else if (AVR_MEGA)
+    return 3;
+  
+  return 2;
+}
+
+/* return a AVR condition jump commands.
+ LEN is a number returned by avr_jump_mode function.  */
+
+char *
+ret_cond_branch (cond,len)
+     RTX_CODE cond;
+     int len;
+{
+  switch (cond)
+    {
+    case GT:
+      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
+       return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
+                           AS1 (brpl,%0)) :
+               len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
+                           AS1 (brmi,_PC_+2) CR_TAB
+                           AS1 (rjmp,%0)) :
+               (AS1 (breq,_PC_+6) CR_TAB
+                AS1 (brmi,_PC_+4) CR_TAB
+                AS1 (jmp,%0)));
+         
+      else
+       return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
+                           AS1 (brge,%0)) :
+               len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
+                           AS1 (brlt,_PC_+2) CR_TAB
+                           AS1 (rjmp,%0)) :
+               (AS1 (breq,_PC_+6) CR_TAB
+                AS1 (brlt,_PC_+4) CR_TAB
+                AS1 (jmp,%0)));
+    case GTU:
+      return (len == 1 ? (AS1 (breq,_PC_+2) CR_TAB
+                          AS1 (brsh,%0)) :
+              len == 2 ? (AS1 (breq,_PC_+4) CR_TAB
+                          AS1 (brlo,_PC_+2) CR_TAB
+                          AS1 (rjmp,%0)) :
+              (AS1 (breq,_PC_+6) CR_TAB
+               AS1 (brlo,_PC_+4) CR_TAB
+               AS1 (jmp,%0)));
+    case LE:
+      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
+       return (len == 1 ? (AS1 (breq,%0) CR_TAB
+                           AS1 (brmi,%0)) :
+               len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
+                           AS1 (brpl,_PC_+2) CR_TAB
+                           AS1 (rjmp,%0)) :
+               (AS1 (breq,_PC_+2) CR_TAB
+                AS1 (brpl,_PC_+4) CR_TAB
+                AS1 (jmp,%0)));
+      else
+       return (len == 1 ? (AS1 (breq,%0) CR_TAB
+                           AS1 (brlt,%0)) :
+               len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
+                           AS1 (brge,_PC_+2) CR_TAB
+                           AS1 (rjmp,%0)) :
+               (AS1 (breq,_PC_+2) CR_TAB
+                AS1 (brge,_PC_+4) CR_TAB
+                AS1 (jmp,%0)));
+    case LEU:
+      return (len == 1 ? (AS1 (breq,%0) CR_TAB
+                          AS1 (brlo,%0)) :
+              len == 2 ? (AS1 (breq,_PC_+2) CR_TAB
+                          AS1 (brsh,_PC_+2) CR_TAB
+                         AS1 (rjmp,%0)) :
+              (AS1 (breq,_PC_+2) CR_TAB
+               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));
+        }
+    }
+  return "";
+}
+
+/* Predicate function for immediate operand which fits to byte (8bit) */
+
+int
+byte_immediate_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return (GET_CODE (op) == CONST_INT
+          && INTVAL (op) <= 0xff && INTVAL (op) >= 0);
+}
+
+/* Output all insn addresses and their sizes into the assembly language
+   output file.  This is helpful for debugging whether the length attributes
+   in the md file are correct.
+   Output insn cost for next insn.  */
+
+void
+final_prescan_insn (insn, operand, num_operands)
+     rtx insn, *operand ATTRIBUTE_UNUSED;
+     int num_operands ATTRIBUTE_UNUSED;
+{
+  int uid = INSN_UID (insn);
+
+  if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
+    {
+      fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", insn_addresses[uid],
+               insn_addresses[uid] - last_insn_address,
+              rtx_cost (PATTERN (insn),INSN));
+    }
+  last_insn_address = insn_addresses[uid];
+
+  if (TARGET_RTL_DUMP)
+    {
+      fprintf (asm_out_file, "/*****************\n");
+      print_rtl_single (asm_out_file, insn);
+      fprintf (asm_out_file, "*****************/\n");
+    }
+}
+
+/* return 1 if undefined,
+   1 if always true or always false  */
+
+int
+avr_simplify_comparision_p (mode, operator, x)
+     enum machine_mode mode;
+     RTX_CODE operator;
+     rtx x;
+{
+  unsigned int max = (mode == QImode ? 0xff :
+                      mode == HImode ? 0xffff :
+                      mode == SImode ? 0xffffffffU : 0);
+  if (max && operator && GET_CODE (x) == CONST_INT)
+    {
+      if (unsigned_condition (operator) != operator)
+       max >>= 1;
+
+      if (max != (INTVAL (x) & max)
+         && INTVAL (x) != 0xff)
+       return 1;
+    }
+  return 0;
+}
+
+
+/* Returns nonzero if REGNO is the number of a hard
+   register in which function arguments are sometimes passed.  */
+
+int
+function_arg_regno_p(r)
+     int r;
+{
+  return (r >= 8 && r <= 25);
+}
+
+/* Initializing the variable cum for the state at the beginning
+   of the argument list.  */
+
+void
+init_cumulative_args (cum, fntype, libname, indirect)
+     CUMULATIVE_ARGS *cum;
+     tree fntype;
+     rtx libname;
+     int indirect ATTRIBUTE_UNUSED;
+{
+  cum->nregs = 18;
+  cum->regno = FIRST_CUM_REG;
+  if (!libname)
+    {
+      int stdarg = (TYPE_ARG_TYPES (fntype) != 0
+                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+                        != void_type_node));
+      if (stdarg)
+        cum->nregs = 0;
+    }
+}
+
+/* Controls whether a function argument is passed
+   in a register, and which register. */
+
+rtx
+function_arg (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named ATTRIBUTE_UNUSED;
+{
+  int bytes;
+
+  bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+
+  if (cum->nregs && bytes <= cum->nregs)
+    return gen_rtx (REG, mode, cum->regno - bytes);
+  return NULL_RTX;
+}
+
+/* Update the summarizer variable CUM to advance past an argument
+   in the argument list.  */
+   
+void
+function_arg_advance (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;      /* current arg information */
+     enum machine_mode mode;    /* current arg mode */
+     tree type;                 /* type of the argument or 0 if lib support */
+     int named ATTRIBUTE_UNUSED; /* whether or not the argument was named */
+{
+  int bytes;
+
+  bytes = (mode == BLKmode ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
+  cum->nregs -= bytes;
+  cum->regno -= bytes;
+
+  if (cum->nregs <= 0)
+    {
+      cum->nregs = 0;
+      cum->regno = FIRST_CUM_REG;
+    }
+
+  return;
+}
+
+/***********************************************************************
+  Functions for outputting various mov's for a various modes
+************************************************************************/
+char *
+out_movqi_r_mr (insn, op, l)
+     rtx insn;
+     rtx op[];
+     int *l; /* instruction length */
+{
+  /* We handle CONSTANT_ADDRESS_P case in adjust_insn_length */
+  if (l) *l=1;
+  if (GET_CODE (op[1]) == MEM)
+    {
+      rtx x = XEXP (op[1],0);
+      if (GET_CODE (x) == PLUS
+         && REG_P (XEXP (x,0))
+         && GET_CODE (XEXP (x,1)) == CONST_INT)
+       {
+         if((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (op[1]))) >= 63)
+           {
+             int disp = INTVAL (XEXP (x,1));
+             if (REGNO (XEXP (x,0)) != REG_Y)
+               fatal_insn ("Incorrect insn:",insn);
+             if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+               {
+                 if (l)
+                   *l = 3;
+                 else
+                   {
+                     op[4] = GEN_INT (disp - 63);
+                     return (AS2 (adiw, r28, %4) CR_TAB
+                             AS2 (ldd, %0,Y+63)  CR_TAB
+                             AS2 (sbiw, r28, %4));
+                   }
+               }
+             else
+               {
+                 op[4] = XEXP (x,1);
+                 if (l)
+                   *l = 5;
+                 else
+                   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)));
+               }
+           }
+         else if (REGNO (XEXP (x,0)) == REG_X)
+           {
+             /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
+                it but I have this situation with extremal optimizing options
+             */
+             if (l)
+               *l=3;
+             else
+               {
+                 output_asm_insn (AS2 (adiw, r26, %0),&XEXP (x,1));
+                 output_asm_insn (AS2 (ld ,%0,X),op);
+                 if (!reg_overlap_mentioned_p (op[0],XEXP (x,0)))
+                   output_asm_insn (AS2 (sbiw, r26, %0),&XEXP (x,1));
+               }
+             return "";
+           }
+       }
+    }
+  return AS2 (ld%K1,%0,%1);
+}
+
+char *
+out_movhi_r_mr (insn, op, l)
+     rtx insn;
+     rtx op[];
+     int *l; /* instruction length */
+{
+  int reg_dest = true_regnum (op[0]);
+  int reg_base = true_regnum (XEXP (op[1],0));
+  int len_p = 1,tmp;
+  int *real_l=l;
+
+  if (!l)
+    l = &tmp, len_p = 0;
+
+  if (reg_base > 0)
+    {
+      if (reg_dest == reg_base)         /* R = (R) */
+        return *l=3, (AS2 (ld,__tmp_reg__,%1+) CR_TAB
+                      AS2 (ld,%B0,%1) CR_TAB
+                      AS2 (mov,%A0,__tmp_reg__));
+      else if (reg_base == REG_X)        /* (R26) */
+        {
+          if (reg_unused_after (insn, XEXP (op[1],0)))
+            return *l=2, (AS2 (ld,%A0,X+) CR_TAB
+                          AS2 (ld,%B0,X));
+          else
+            return *l=3, (AS2 (ld,%A0,X+) CR_TAB
+                          AS2 (ld,%B0,X) CR_TAB
+                          AS2 (sbiw,r26,1));
+        }
+      else                      /* (R)  */
+        return  *l=2, (AS2 (ld,%A0,%1)    CR_TAB
+                       AS2 (ldd,%B0,%1+1));
+    }
+  else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+    {
+      int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
+      int reg_base = true_regnum (XEXP (XEXP (op[1],0), 0));
+      
+      if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+       {
+         rtx x = XEXP (op[1],0);
+         if (REGNO (XEXP (x,0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+         if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+           {
+             op[4] = GEN_INT (disp - 62);
+             return *l=4, (AS2 (adiw, r28, %4) CR_TAB
+                           AS2 (ldd, %A0,Y+62)       CR_TAB
+                           AS2 (ldd, %B0,Y+63)     CR_TAB
+                           AS2 (sbiw, r28, %4));
+           }
+         else
+           {
+             op[4] = XEXP (x,1);
+             return *l=6, (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)));
+           }
+       }
+      if (reg_base == REG_X)
+       {
+         /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
+            it but I have this situation with extremal optimization options
+          */
+         rtx ops[1];
+         ops[0] = XEXP (XEXP (op[1],0), 1);
+         if (real_l)
+           *l = 4;
+         else if (reg_base == reg_dest)
+           {
+             output_asm_insn (AS2 (adiw, r26, %0), ops);
+             output_asm_insn (AS2 (ld , __tmp_reg__, X+), op);
+             output_asm_insn (AS2 (ld , %B0, X), op);
+             output_asm_insn (AS2 (mov, %A0, __tmp_reg__),op);
+           }
+         else
+           {
+             output_asm_insn (AS2 (adiw, r26, %0), ops);
+             output_asm_insn (AS2 (ld , %A0, X+), op);
+             output_asm_insn (AS2 (ld , %B0, X), op);
+             if (INTVAL (ops[0]) == 63)
+               {
+                 output_asm_insn (AS2 (subi, r26, %0+1), ops);
+                 output_asm_insn (AS2 (sbci, r26, 0), ops);
+               }
+             else
+               output_asm_insn (AS2 (sbiw, r26, %0+1), ops);
+           }
+         return "";
+       }
+      
+      if (reg_base == reg_dest)        
+       return *l=3, (AS2 (ldd,__tmp_reg__,%A1)    CR_TAB
+                     AS2 (ldd,%B0,%B1)   CR_TAB
+                     AS2 (mov,%A0,__tmp_reg__));
+      else
+       return *l=2, (AS2 (ldd,%A0,%A1)    CR_TAB
+                     AS2 (ldd,%B0,%B1));
+    }
+  else if (GET_CODE (XEXP (op[1],0)) == PRE_DEC) /* (--R) */
+    {
+      if (reg_overlap_mentioned_p (op[0], XEXP (XEXP (op[1],0),0)))
+       {
+         debug_rtx (insn);
+         fatal ("Internal error. Incorrect insn.");
+       }
+      return *l=2, (AS2 (ld,%B0,%1) CR_TAB
+                   AS2 (ld,%A0,%1));
+    }
+  else if (GET_CODE (XEXP (op[1],0)) == POST_INC) /* (R++) */
+    {
+      if (reg_overlap_mentioned_p (op[0], XEXP (XEXP (op[1],0),0)))
+       {
+         debug_rtx (insn);
+         fatal ("Internal error. Incorrect insn.");
+       }
+      return *l=2, (AS2 (ld,%A0,%1)  CR_TAB
+                   AS2 (ld,%B0,%1));
+    }
+  else if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
+        return *l=4, (AS2 (lds,%A0,%A1) CR_TAB
+                     AS2 (lds,%B0,%B1));
+  fatal_insn ("Unknown move insn:",insn);
+  return "";
+}
+
+char *
+out_movsi_r_mr (insn,op,l)
+     rtx insn;
+     rtx op[];
+     int *l; /* instruction length */
+{
+  int reg_dest=true_regnum (op[0]);
+  int reg_base=true_regnum (XEXP (op[1],0));
+  int tmp;
+  if (!l)
+    l=&tmp;
+  if (reg_base > 0)
+    {
+      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__));
+          else if (reg_dest == REG_X - 2)
+            return *l=5, (AS2 (ld,%A0,X+)  CR_TAB
+                          AS2 (ld,%B0,X+) CR_TAB
+                          AS2 (ld,__tmp_reg__,X+)  CR_TAB
+                          AS2 (ld,%D0,X)  CR_TAB
+                          AS2 (mov,%C0,__tmp_reg__));
+          else if (reg_unused_after (insn,XEXP (op[1],0)))
+            return  *l=4, (AS2 (ld,%A0,X+)  CR_TAB
+                           AS2 (ld,%B0,X+) CR_TAB
+                           AS2 (ld,%C0,X+) CR_TAB
+                           AS2 (ld,%D0,X));
+          else
+            return  *l=5, (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,3));
+        }
+      else
+        {
+          if (reg_dest == reg_base)
+            return *l=5, (AS2 (ldd,%D0,%1+3) CR_TAB
+                          AS2 (ldd,%C0,%1+2) CR_TAB
+                          AS2 (ldd,__tmp_reg__,%1+1)  CR_TAB
+                          AS2 (ld,%A0,%1)  CR_TAB
+                          AS2 (mov,%B0,__tmp_reg__));
+          else if (reg_base == reg_dest + 2)
+            return *l=5, (AS2 (ld ,%A0,%1)    CR_TAB
+                          AS2 (ldd,%B0,%1+1) CR_TAB
+                          AS2 (ldd,__tmp_reg__,%1+2)  CR_TAB
+                          AS2 (ldd,%D0,%1+3) CR_TAB
+                          AS2 (mov,%C0,__tmp_reg__));
+          else
+            return *l=4, (AS2 (ld ,%A0,%1)   CR_TAB
+                          AS2 (ldd,%B0,%1+1) CR_TAB
+                          AS2 (ldd,%C0,%1+2) CR_TAB
+                          AS2 (ldd,%D0,%1+3));
+        }
+    }
+  else if (GET_CODE (XEXP (op[1],0)) == PLUS) /* (R + i) */
+    {
+      int disp = INTVAL(XEXP (XEXP (op[1],0), 1));
+      
+      if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+       {
+         rtx x = XEXP (op[1],0);
+         if (REGNO (XEXP (x,0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+         if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[1])))
+           {
+             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 (x,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)));
+           }
+       }
+
+      reg_base = true_regnum (XEXP (XEXP (op[1],0), 0));
+      if (reg_dest == reg_base)
+        return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
+                      AS2 (ldd,%C0,%C1) CR_TAB
+                      AS2 (ldd,__tmp_reg__,%B1)  CR_TAB
+                      AS2 (ldd,%A0,%A1) CR_TAB
+                      AS2 (mov,%B0,__tmp_reg__));
+      else if (reg_dest == reg_base - 2)
+        return *l=5, (AS2 (ldd,%A0,%A1) CR_TAB
+                      AS2 (ldd,%B0,%B1) CR_TAB
+                      AS2 (ldd,__tmp_reg__,%C1)  CR_TAB
+                      AS2 (ldd,%D0,%D1) CR_TAB
+                      AS2 (mov,%C0,__tmp_reg__));
+      return *l=4, (AS2 (ldd,%A0,%A1) CR_TAB
+                    AS2 (ldd,%B0,%B1) CR_TAB
+                    AS2 (ldd,%C0,%C1) CR_TAB
+                    AS2 (ldd,%D0,%D1));
+    }
+  else if (GET_CODE (XEXP (op[1],0)) == PRE_DEC) /* (--R) */
+    return *l=4, (AS2 (ld,%D0,%1) CR_TAB
+                 AS2 (ld,%C0,%1) CR_TAB
+                 AS2 (ld,%B0,%1) CR_TAB
+                 AS2 (ld,%A0,%1));
+  else if (GET_CODE (XEXP (op[1],0)) == POST_INC) /* (R++) */
+    return *l=4, (AS2 (ld,%A0,%1) CR_TAB
+                 AS2 (ld,%B0,%1) CR_TAB
+                 AS2 (ld,%C0,%1) CR_TAB
+                 AS2 (ld,%D0,%1));
+  else if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
+      return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
+                   AS2 (lds,%B0,%B1) CR_TAB
+                   AS2 (lds,%C0,%C1) CR_TAB
+                   AS2 (lds,%D0,%D1));
+    
+  fatal_insn ("Unknown move insn:",insn);
+  return "";
+}
+
+char *
+out_movsi_mr_r (insn,op,l)
+     rtx insn;
+     rtx op[];
+     int *l;
+{
+  int reg_base = true_regnum (XEXP (op[0],0));
+  int reg_dest = true_regnum (op[1]);
+  int tmp;
+  if (!l)
+    l = &tmp;
+  if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
+    return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
+                AS2 (sts,%B0,%B1) CR_TAB
+                AS2 (sts,%C0,%C1) CR_TAB
+                AS2 (sts,%D0,%D1));
+  if (reg_base > 0)                 /* (r) */
+    {
+      if (reg_base == REG_X)                /* (R26) */
+        {
+          if (reg_dest == REG_X)
+            {
+              if (reg_unused_after (insn,XEXP (op[0],0)))
+                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));
+              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));
+            }
+          else if (reg_base == reg_dest+2)
+            {
+              if (reg_unused_after (insn,XEXP (op[0],0)))
+                return *l=7, (AS2 (mov,__zero_reg__,%C1) CR_TAB
+                              AS2 (mov,__tmp_reg__,%D1) CR_TAB
+                              AS2 (st,%0+,%A1) CR_TAB
+                              AS2 (st,%0+,%B1) CR_TAB
+                              AS2 (st,%0+,__zero_reg__)  CR_TAB
+                              AS2 (st,%0,__tmp_reg__)   CR_TAB
+                              AS1 (clr,__zero_reg__));
+              else
+                return *l=8, (AS2 (mov,__zero_reg__,%C1) CR_TAB
+                              AS2 (mov,__tmp_reg__,%D1) CR_TAB
+                              AS2 (st,%0+,%A1) CR_TAB
+                              AS2 (st,%0+,%B1) CR_TAB
+                              AS2 (st,%0+,__zero_reg__)  CR_TAB
+                              AS2 (st,%0,__tmp_reg__)   CR_TAB
+                              AS1 (clr,__zero_reg__)     CR_TAB
+                              AS2 (sbiw,r26,3));
+            }
+          return *l=5, (AS2 (st,%0+,%A1)  CR_TAB
+                        AS2 (st,%0+,%B1) CR_TAB
+                        AS2 (st,%0+,%C1) CR_TAB
+                        AS2 (st,%0,%D1)  CR_TAB
+                        AS2 (sbiw,r26,3));
+        }
+      else
+        return *l=4, (AS2 (st,%0,%A1)    CR_TAB
+                     AS2 (std,%0+1,%B1) CR_TAB
+                     AS2 (std,%0+2,%C1) CR_TAB
+                     AS2 (std,%0+3,%D1));
+    }
+  else if (GET_CODE (XEXP (op[0],0)) == PLUS) /* (R + i) */
+    {
+      int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
+      if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+       {
+         rtx x = XEXP (op[0],0);
+         if (REGNO (XEXP (x,0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+         if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+           {
+             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));
+           }
+         else
+           {
+             op[4] = XEXP (x,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)));
+           }
+       }
+      return *l=4, (AS2 (std,%A0,%A1)    CR_TAB
+                   AS2 (std,%B0,%B1) CR_TAB
+                   AS2 (std,%C0,%C1) CR_TAB
+                   AS2 (std,%D0,%D1));
+    }
+  else if (GET_CODE (XEXP (op[0],0)) == PRE_DEC) /* (--R) */
+    return *l=4, (AS2 (st,%0,%D1) CR_TAB
+                 AS2 (st,%0,%C1) CR_TAB
+                 AS2 (st,%0,%B1) CR_TAB
+                 AS2 (st,%0,%A1));
+  else if (GET_CODE (XEXP (op[0],0)) == POST_INC) /* (R++) */
+    return *l=4, (AS2 (st,%0,%A1)  CR_TAB
+                 AS2 (st,%0,%B1) CR_TAB
+                 AS2 (st,%0,%C1) CR_TAB
+                 AS2 (st,%0,%D1));
+  fatal_insn ("Unknown move insn:",insn);
+  return "";
+}
+
+char *
+output_movsisf(insn, operands, which_alternative)
+     rtx insn;
+     rtx operands[];
+     int which_alternative;
+{
+  rtx link;
+  switch (which_alternative)
+    {
+    case 0: /* mov r,r */
+      if (true_regnum (operands[0]) > true_regnum (operands[1]))
+        return (AS2 (mov,%D0,%D1) CR_TAB
+               AS2 (mov,%C0,%C1) CR_TAB
+               AS2 (mov,%B0,%B1) CR_TAB
+               AS2 (mov,%A0,%A1));
+      else
+        return (AS2 (mov,%A0,%A1) CR_TAB
+               AS2 (mov,%B0,%B1) CR_TAB
+               AS2 (mov,%C0,%C1) CR_TAB
+               AS2 (mov,%D0,%D1));
+    case 1:  /* mov r,L */
+      return (AS1 (clr,%A0) CR_TAB
+             AS1 (clr,%B0) CR_TAB
+             AS1 (clr,%C0) CR_TAB
+             AS1 (clr,%D0));
+    case 2: /* mov r,d */
+      if (GET_MODE (operands[0]) == SImode
+         && operands[1] == const1_rtx
+         && (link = find_reg_note (insn, REG_WAS_0, 0))
+         /* Make sure the insn that stored the 0 is still present.  */
+         && ! INSN_DELETED_P (XEXP (link, 0))
+         && GET_CODE (XEXP (link, 0)) != NOTE
+         /* Make sure cross jumping didn't happen here.  */
+         && no_labels_between_p (XEXP (link, 0), insn)
+         /* Make sure the reg hasn't been clobbered.  */
+         && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
+      /* Fastest way to change a 0 to a 1.  */
+        return AS1 (inc,%A0 ; reg_was_0);
+      return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
+             AS2 (ldi,%B0,hi8(%1)) CR_TAB
+             AS2 (ldi,%C0,hlo8(%1)) CR_TAB
+             AS2 (ldi,%D0,hhi8(%1)));
+    case 3: /* mov r,m*/
+    case 5:
+      return out_movsi_r_mr (insn, operands, NULL);
+    case 4: /* mov m,r*/
+    case 6:
+      {
+       rtx save1=NULL;
+       if (operands[1] == const0_rtx)
+         {
+           save1 = operands[1];
+           operands[1] = zero_reg_rtx;
+         }
+       output_asm_insn (out_movsi_mr_r (insn,operands,NULL), operands);
+       if (save1)
+         operands[1] = save1;
+      }
+    }
+  return "";
+}
+
+char *
+out_movqi_mr_r (insn, op, l)
+     rtx insn;
+     rtx op[];
+     int *l; /* instruction length */
+{
+  if (l) *l=1;
+
+  if (GET_CODE (op[0]) == MEM)
+    {
+      rtx x = XEXP (op[0],0);
+      if (GET_CODE (x) == PLUS
+         && REG_P (XEXP (x,0))
+         && GET_CODE (XEXP (x,1)) == CONST_INT)
+       {
+         if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (op[0]))) >= 63)
+           {
+             int disp = INTVAL (XEXP (x,1));
+             if (REGNO (XEXP (x,0)) != REG_Y)
+               fatal_insn ("Incorrect insn:",insn);
+             if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+               {
+                 if (l)
+                   *l = 3;
+                 else
+                   {
+                     op[4] = GEN_INT (disp - 63);
+                     return (AS2 (adiw, r28, %4) CR_TAB
+                             AS2 (std, Y+63,%1)        CR_TAB
+                             AS2 (sbiw, r28, %4));
+                   }
+               }
+             else
+               {
+                 op[4] = XEXP (x,1);
+                 if (l)
+                   *l = 5;
+                 else
+                   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)));
+               }
+           }
+         else if (REGNO (XEXP (x,0)) == REG_X)
+           {
+             if (l)
+               *l=4;
+             else
+               {
+                 int overlap_p = reg_overlap_mentioned_p (op[1],XEXP (x,0));
+                 if (!overlap_p)
+                   output_asm_insn (AS2 (mov, __tmp_reg__, %1),op);
+                 output_asm_insn (AS2 (adiw, r26,%0),&XEXP (x,1));
+                 if (overlap_p)
+                   output_asm_insn (AS2 (st ,X,__tmp_reg__),op);
+                 else
+                   output_asm_insn (AS2 (st ,X,%1),op);
+                 output_asm_insn (AS2 (sbiw ,r26,%0),&XEXP (x,1));
+               }
+             return "";
+           }
+       }
+    }
+  return AS2 (st%K0, %0,%1);
+}
+
+char *
+out_movhi_mr_r (insn,op,l)
+     rtx insn;
+     rtx op[];
+     int *l;
+{
+  int reg_base = true_regnum (XEXP (op[0],0));
+  int reg_dest = true_regnum (op[1]);
+  int tmp;
+  if (!l)
+    l = &tmp;
+  if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
+    return *l=4,(AS2 (sts,%A0,%A1) CR_TAB
+                AS2 (sts,%B0,%B1));
+  if (reg_base > 0)
+    {
+      if (reg_base == REG_X)
+        {
+          if (reg_dest == REG_X)
+            {
+              if (reg_unused_after (insn, op[1]))
+                return *l=3, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+                              AS2 (st ,X+,r26) 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));
+            }
+          else
+            {
+              if (reg_unused_after (insn, XEXP (op[0],0)))
+                return *l=2, (AS2 (st,X+,%A1) CR_TAB
+                              AS2 (st,X,%B1));
+              else
+                return *l=3, (AS2 (st  ,X+,%A1) CR_TAB
+                              AS2 (st  ,X,%B1) CR_TAB
+                              AS2 (sbiw,r26,1));
+            }
+        }
+      else
+        return  *l=2, (AS2 (st ,%0,%A1)    CR_TAB
+                       AS2 (std,%0+1,%B1));
+    }
+  else if (GET_CODE (XEXP (op[0],0)) == PLUS)
+    {
+      int disp = INTVAL(XEXP (XEXP (op[0],0), 1));
+      if (disp > 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+       {
+         rtx x = XEXP (op[0],0);
+         if (REGNO (XEXP (x,0)) != REG_Y)
+           fatal_insn ("Incorrect insn:",insn);
+         if (disp <= 63 + 64 - GET_MODE_SIZE (GET_MODE (op[0])))
+           {
+             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 (x,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)));
+           }
+       }
+      return *l=2, (AS2 (std,%A0,%A1)    CR_TAB
+                   AS2 (std,%B0,%B1));
+    }  
+  else if (GET_CODE (XEXP (op[0],0)) == PRE_DEC) /* (--R) */
+    return *l=2, (AS2 (st,%0,%B1) CR_TAB
+                 AS2 (st,%0,%A1));
+  else if (GET_CODE (XEXP (op[0],0)) == POST_INC) /* (R++) */
+    return *l=2, (AS2 (st,%0,%A1)  CR_TAB
+                 AS2 (st,%0,%B1));
+  fatal_insn ("Unknown move insn:",insn);
+  return "";
+}
+
+/* Return 1 if frame pointer for current function required */
+
+int
+frame_pointer_required_p(void)
+{
+  return (current_function_calls_alloca
+         || current_function_args_info.nregs == 0
+         || current_function_varargs
+         || get_frame_size () > 0);
+}
+
+/* Return 1 if the next insn is a JUMP_INSN with condition (GT,LE,GTU,LTU)  */
+
+int
+compare_diff_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);
+    }
+  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 */
+
+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);
+    }
+  return (cond == EQ || cond == NE);
+}
+
+
+/* Output test instruction for HImode */
+
+char *
+out_tsthi (insn,l)
+     rtx insn;
+     int *l;
+{
+  if (!compare_eq_p (insn))
+    {
+      if (l) *l = 1;
+      return AS1 (tst,%B0);
+    }
+  if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+    {
+      if (l) *l = 1;
+      return AS2 (sbiw,%0,0);
+    }
+  if (compare_eq_p (insn) && reg_unused_after (insn, SET_SRC (PATTERN (insn))))
+    {
+      if (l) *l = 1;
+      return AS2 (or,%A0,%B0);
+    }
+  if (l) *l = 2;
+  return (AS2 (cp,%A0,__zero_reg__) CR_TAB
+          AS2 (cpc,%B0,__zero_reg__));
+}
+
+
+/* Output test instruction for SImode */
+
+char *
+out_tstsi (insn,l)
+     rtx insn;
+     int *l;
+{
+  if (!compare_eq_p (insn))
+    {
+      if (l) *l = 1;
+      return AS1 (tst,%D0);
+    }
+  if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (SET_SRC (PATTERN (insn)))))
+    {
+      if (l) *l = 3;
+      return (AS2 (sbiw,%A0,0) CR_TAB
+              AS2 (cpc,%C0,__zero_reg__) CR_TAB
+              AS2 (cpc,%D0,__zero_reg__));
+    }
+  if (l) *l = 4;
+  return (AS2 (cp,%A0,__zero_reg__) CR_TAB
+          AS2 (cpc,%B0,__zero_reg__) CR_TAB
+          AS2 (cpc,%C0,__zero_reg__) CR_TAB
+          AS2 (cpc,%D0,__zero_reg__));
+}
+
+
+/* Generate asm equivalent for various shift's.
+   Shift count are CONST_INT or REG.  */
+
+void
+out_shift_with_cnt (template,insn,operands,len)
+     char * template;
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  rtx op[10];
+  int l_hi=0;
+  char str[300];
+  op[0] = operands[0];
+  op[1] = operands[1];
+  op[2] = operands[2];
+  op[3] = operands[3];
+  str[0] = 0;
+    
+  if (CONSTANT_P (operands[2]))
+    {
+      if (len)
+       ++*len;
+      else
+       strcat (str, "ldi %3,lo8(%2)");
+    }
+  else if (GET_CODE (operands[2]) == MEM)
+    {
+      int mov_len;
+      rtx op_mov[10];
+      l_hi = 1;
+      if (len)
+       *len = 2;
+      op[3] = op_mov[0] = tmp_reg_rtx;
+      op_mov[1] = op[2];
+      
+      if (!len)
+       {
+         output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
+         strcat (str,(AS2 (or,%3,%3)    CR_TAB
+                      AS1 (breq,L_hi%=)));
+       }
+      else
+       {
+         out_movqi_r_mr (insn, op_mov, &mov_len);
+         *len += mov_len;
+       }
+    }
+  else if (register_operand (operands[2],QImode))
+    {
+      l_hi = 1;
+      if (len)
+       *len += 2;
+      else
+       strcat (str, (AS2 (or,%2,%2) CR_TAB
+                     AS1 (breq,L_hi%=)));
+      
+      if (reg_unused_after (insn, operands[2]))
+       {
+         op[3] = op[2];
+       }
+      else
+       {
+         op[3] = tmp_reg_rtx;
+         if (len)
+           ++*len;
+         else
+           strcat (str, CR_TAB "mov %3,%2");
+       }
+    }
+  if (!len)
+    {
+      strcat (str,"\n\t");
+      strcat (str, template);
+      if (l_hi)
+       strcat (str, "\nL_hi%=:");
+      output_asm_insn (str, op);
+    }
+}
+
+
+/* 8bit shift left ((char)x << i)   */
+
+char *
+ashlqi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;                 /* insn length (may be NULL) */
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=1;
+         return AS1 (lsl,%0);
+       case 2:
+         *len=2;
+         return (AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0));
+       case 3:
+         *len=3;
+         return (AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0));
+       case 4:
+         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+           {
+             *len=2;
+             return (AS1 (swap,%0) CR_TAB
+                     AS2 (andi,%0,0xf0));
+           }
+         *len=4;
+         return (AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0));
+       case 5:
+         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+           {
+             *len=3;
+             return (AS1 (swap,%0) CR_TAB
+                     AS1 (lsl,%0)  CR_TAB
+                     AS2 (andi,%0,0xe0));
+           }
+         *len=5;
+         return (AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0));
+       case 6:
+         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+           {
+             *len=4;
+             return (AS1 (swap,%0) CR_TAB
+                     AS1 (lsl,%0)  CR_TAB
+                     AS1 (lsl,%0)  CR_TAB
+                     AS2 (andi,%0,0xc0));
+           }
+         *len=6;
+         return (AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0) CR_TAB
+                 AS1 (lsl,%0));
+       case 7:
+         *len=3;
+         return (AS1 (ror,%0) CR_TAB
+                 AS1 (clr,%0) CR_TAB
+                 AS1 (ror,%0));
+       }
+    }
+  if (len)
+    *len = 3;
+  out_shift_with_cnt (AS1 (lsl,%0)      CR_TAB
+                     AS1 (dec,%3)      CR_TAB
+                     AS1 (brne,_PC_-6),
+                     insn, operands, len);
+  return "";
+}
+
+
+/* 16bit shift left ((short)x << i)   */
+
+char *
+ashlhi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=2;
+         return (AS1 (lsl,%A0) CR_TAB
+                 AS1 (rol,%B0));
+       case 2:
+         *len=4;
+         return (AS1 (lsl,%A0) CR_TAB
+                 AS1 (rol,%B0) CR_TAB
+                 AS1 (lsl,%0)  CR_TAB
+                 AS1 (rol,%B0));
+       case 8:
+         if (true_regnum (operands[0]) + 1 == true_regnum (operands[1]))
+           return *len = 1, AS1 (clr,%A0);
+         else
+           return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
+                             AS1 (clr,%A0));
+       }
+    }
+  if (len)
+    *len = 4;
+  out_shift_with_cnt (AS1 (lsl,%0)  CR_TAB
+                     AS1 (rol,%B0) CR_TAB
+                     AS1 (dec,%3)  CR_TAB
+                     AS1 (brne,_PC_-8),
+                     insn, operands, len);
+  return "";
+}
+
+
+/* 32bit shift left ((long)x << i)   */
+
+char *
+ashlsi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=4;
+         return (AS1 (lsl,%A0) CR_TAB
+                 AS1 (rol,%B0) CR_TAB
+                 AS1 (rol,%C0) CR_TAB
+                 AS1 (rol,%D0));
+       case 8:
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+           *len=4;
+           if (reg0 >= reg1)
+             return (AS2 (mov,%D0,%C1)  CR_TAB
+                     AS2 (mov,%C0,%B1)  CR_TAB
+                     AS2 (mov,%B0,%A1)  CR_TAB
+                     AS1 (clr,%A0));
+           else if (reg0 + 1 == reg1)
+             return *len = 1, AS1 (clr,%A0);
+           else
+             return (AS1 (clr,%A0)      CR_TAB
+                     AS2 (mov,%B0,%A1)  CR_TAB
+                     AS2 (mov,%C0,%B1)  CR_TAB
+                     AS2 (mov,%D0,%C1));
+         }
+       case 16:
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+           *len=4;
+           if (reg0 + 1 >= reg1)
+             return (AS2 (mov,%D0,%B1)  CR_TAB
+                     AS2 (mov,%C0,%A1)  CR_TAB
+                     AS1 (clr,%B0)      CR_TAB
+                     AS1 (clr,%A0));
+           if (reg0 + 2 == reg1)
+             return *len = 2, (AS1 (clr,%B0)      CR_TAB
+                               AS1 (clr,%A0));
+           else
+             return (AS2 (mov,%C0,%A1)  CR_TAB
+                     AS2 (mov,%D0,%B1)  CR_TAB
+                     AS1 (clr,%B0)      CR_TAB
+                     AS1 (clr,%A0));
+         }
+       case 24:
+         *len=4;
+         if (true_regnum (operands[0]) + 3 != true_regnum (operands[1]))
+           return (AS2 (mov,%D0,%A1)  CR_TAB
+                   AS1 (clr,%C0)      CR_TAB
+                   AS1 (clr,%B0)      CR_TAB
+                   AS1 (clr,%A0));
+         else
+           return *len = 3, (AS1 (clr,%C0)      CR_TAB
+                             AS1 (clr,%B0)      CR_TAB
+                             AS1 (clr,%A0));
+       }
+    }
+  if (len)
+    *len = 6;
+  out_shift_with_cnt (AS1 (lsl,%0)  CR_TAB
+                     AS1 (rol,%B0) CR_TAB
+                     AS1 (rol,%C0) CR_TAB
+                     AS1 (rol,%D0) CR_TAB
+                     AS1 (dec,%3)  CR_TAB
+                     AS1 (brne,_PC_-12),
+                     insn, operands, len);
+  return "";
+}
+
+/* 8bit arithmetic shift right  ((signed char)x >> i) */
+
+char *
+ashrqi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len; /* insn length */
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int *t=len;
+      int k;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=1;
+         return AS1 (asr,%0);
+       case 2:
+         *len=2;
+         return (AS1 (asr,%0) CR_TAB
+                 AS1 (asr,%0));
+       case 3:
+         *len=3;
+         return (AS1 (asr,%0) CR_TAB
+                 AS1 (asr,%0) CR_TAB
+                 AS1 (asr,%0));
+       case 4:
+         *len=4;
+         return (AS1 (asr,%0) CR_TAB
+                 AS1 (asr,%0) CR_TAB
+                 AS1 (asr,%0) CR_TAB
+                 AS1 (asr,%0));
+       }
+    }
+  if (len)
+    *len = 3;
+  out_shift_with_cnt (AS1 (asr,%0) CR_TAB
+                     AS1 (dec,%3) CR_TAB
+                     AS1 (brne,_PC_-6),
+                     insn, operands, len);
+  return "";
+}
+
+
+/* 16bit arithmetic shift right  ((signed short)x >> i) */
+
+char *
+ashrhi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=2;
+         return (AS1 (asr,%B0) CR_TAB
+                 AS1 (ror,%A0));
+       case 2:
+         *len=4;
+         return (AS1 (asr,%B0)  CR_TAB
+                 AS1 (ror,%A0) CR_TAB
+                 AS1 (asr,%B0)  CR_TAB
+                 AS1 (ror,%A0));
+       case 8:
+         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
+           return *len = 4, (AS2 (mov,%A0,%B1) CR_TAB
+                             AS1 (clr,%B0)     CR_TAB
+                             AS2 (sbrc,%A0,7)  CR_TAB
+                             AS1 (dec,%B0));
+         else
+           return *len = 3, (AS1 (clr,%B0)     CR_TAB
+                             AS2 (sbrc,%A0,7)  CR_TAB
+                             AS1 (dec,%B0));
+       }
+    }
+  if (len)
+    *len = 4;
+  out_shift_with_cnt (AS1 (asr,%B0) CR_TAB
+                     AS1 (ror,%A0) CR_TAB
+                     AS1 (dec,%3) CR_TAB
+                     AS1 (brne,_PC_-8),
+                     insn, operands, len);
+  return "";
+}
+
+
+/* 32bit arithmetic shift right  ((signed long)x >> i) */
+
+char *
+ashrsi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t = len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=4;
+         return (AS1 (asr,%D0)  CR_TAB
+                 AS1 (ror,%C0) CR_TAB
+                 AS1 (ror,%B0) CR_TAB
+                 AS1 (ror,%A0));
+       case 8:
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+           *len=6;
+           if (reg0 <= reg1)
+             return (AS2 (mov,%A0,%B1) CR_TAB
+                     AS2 (mov,%B0,%C1) CR_TAB
+                     AS2 (mov,%C0,%D1) CR_TAB
+                     AS1 (clr,%D0)     CR_TAB
+                     AS2 (sbrc,%C0,7)  CR_TAB
+                     AS1 (dec,%D0));
+           else if (reg0 == reg1 + 1)
+             return *len = 3, (AS1 (clr,%D0)     CR_TAB
+                               AS2 (sbrc,%C0,7)  CR_TAB
+                               AS1 (dec,%D0));
+           else
+             return (AS1 (clr,%D0)     CR_TAB
+                     AS2 (sbrc,%C0,7)  CR_TAB
+                     AS1 (dec,%D0)     CR_TAB
+                     AS2 (mov,%C0,%D1) CR_TAB
+                     AS2 (mov,%B0,%C1) CR_TAB
+                     AS2 (mov,%A0,%B1));
+         }
+       case 16:
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+           *len=6;
+           if (reg0 <= reg1 + 1)
+             return (AS2 (mov,%A0,%C1) CR_TAB
+                     AS2 (mov,%B0,%D1) CR_TAB
+                     AS1 (clr,%D0)     CR_TAB
+                     AS2 (sbrc,%B0,7)  CR_TAB
+                     AS1 (com,%D0)     CR_TAB
+                     AS2 (mov,%C0,%D0));
+           else if (reg0 == reg1 + 2)
+             return *len = 4, (AS1 (clr,%D0)     CR_TAB
+                               AS2 (sbrc,%B0,7)  CR_TAB
+                               AS1 (com,%D0)     CR_TAB
+                               AS2 (mov,%C0,%D0));
+           else
+             return (AS2 (mov,%B0,%D1) CR_TAB
+                     AS2 (mov,%A0,%C1) CR_TAB
+                     AS1 (clr,%D0)     CR_TAB
+                     AS2 (sbrc,%B0,7)  CR_TAB
+                     AS1 (com,%D0)     CR_TAB
+                     AS2 (mov,%C0,%D0));
+         }
+       case 24:
+         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
+           return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
+                             AS1 (clr,%D0)     CR_TAB
+                             AS2 (sbrc,%A0,7)  CR_TAB
+                             AS1 (com,%D0)     CR_TAB
+                             AS2 (mov,%B0,%D0) CR_TAB
+                             AS2 (mov,%C0,%D0));
+         else
+           return *len = 5, (AS1 (clr,%D0)     CR_TAB
+                             AS2 (sbrc,%A0,7)  CR_TAB
+                             AS1 (com,%D0)     CR_TAB
+                             AS2 (mov,%B0,%D0) CR_TAB
+                             AS2 (mov,%C0,%D0));
+       }
+    }
+  if (len)
+    *len = 6;
+  out_shift_with_cnt (AS1 (asr,%D0) CR_TAB
+                     AS1 (ror,%C0) CR_TAB
+                     AS1 (ror,%B0) CR_TAB
+                     AS1 (ror,%A0) CR_TAB
+                     AS1 (dec,%3) CR_TAB
+                     AS1 (brne,_PC_-12),
+                     insn, operands, len);
+  return "";
+}
+
+/* 8bit logic shift right ((unsigned char)x >> i) */
+
+char *
+lshrqi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=1;
+         return AS1 (lsr,%0);
+       case 2:
+         *len=2;
+         return (AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0));
+       case 3:
+         *len=3;
+         return (AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0));
+       case 4:
+         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+           {
+             *len=2;
+             return (AS1 (swap,%0) CR_TAB
+                     AS2 (andi,%0,0x0f));
+           }
+         *len=4;
+         return (AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0));
+       case 5:
+         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+           {
+             *len=3;
+             return (AS1 (swap,%0) CR_TAB
+                     AS1 (lsr,%0)  CR_TAB
+                     AS2 (andi,%0,0x7));
+           }
+         *len=5;
+         return (AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0));
+       case 6:
+         if (TEST_HARD_REG_CLASS (LD_REGS, true_regnum (operands[0])))
+           {
+             *len=4;
+             return (AS1 (swap,%0) CR_TAB
+                     AS1 (lsr,%0)  CR_TAB
+                     AS1 (lsr,%0)  CR_TAB
+                     AS2 (andi,%0,0x3));
+           }
+         *len=6;
+         return (AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0) CR_TAB
+                 AS1 (lsr,%0));
+       case 7:
+         *len=3;
+         return (AS1 (rol,%0) CR_TAB
+                 AS1 (clr,%0) CR_TAB
+                 AS1 (rol,%0));
+       }
+    }
+  if (len)
+    *len = 3;
+  out_shift_with_cnt (AS1 (lsr,%0) CR_TAB
+                     AS1 (dec,%3) CR_TAB
+                     AS1 (brne,_PC_-6),
+                     insn, operands, len);
+  return "";
+}
+
+/* 16bit logic shift right ((unsigned short)x >> i) */
+
+char *
+lshrhi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=2;
+         return (AS1 (lsr,%B0) CR_TAB
+                 AS1 (ror,%A0));
+       case 2:
+         *len=4;
+         return (AS1 (lsr,%B0)  CR_TAB
+                 AS1 (ror,%A0)  CR_TAB
+                 AS1 (lsr,%B0)  CR_TAB
+                 AS1 (ror,%A0));
+       case 8:
+         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
+           return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
+                             AS1 (clr,%B0));
+         else
+           return *len = 1, AS1 (clr,%B0);
+           
+       }
+    }
+  if (len)
+    *len = 4;
+  out_shift_with_cnt (AS1 (lsr,%B0) CR_TAB
+                     AS1 (ror,%A0) CR_TAB
+                     AS1 (dec,%3) CR_TAB
+                     AS1 (brne,_PC_-8),
+                     insn, operands, len);
+  return "";
+}
+
+/* 32bit logic shift right ((unsigned int)x >> i) */
+
+char *
+lshrsi3_out (insn,operands,len)
+     rtx insn;
+     rtx operands[];
+     int *len;
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      int k;
+      int *t=len;
+      if (!len)
+       len = &k;
+      switch (INTVAL (operands[2]))
+       {
+       default: len = t; break;
+       case 1:
+         *len=4;
+         return (AS1 (lsr,%D0)  CR_TAB
+                 AS1 (ror,%C0) CR_TAB
+                 AS1 (ror,%B0) CR_TAB
+                 AS1 (ror,%A0));
+       case 8:
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+           *len=4;
+           if (reg0 <= reg1)
+             return (AS2 (mov,%A0,%B1) CR_TAB
+                     AS2 (mov,%B0,%C1) CR_TAB
+                     AS2 (mov,%C0,%D1) CR_TAB
+                     AS1 (clr,%D0));
+           else if (reg0 == reg1 + 1)
+             return *len = 1, AS1 (clr,%D0);
+           else
+             return (AS1 (clr,%D0)     CR_TAB
+                     AS2 (mov,%C0,%D1) CR_TAB
+                     AS2 (mov,%B0,%C1) CR_TAB
+                     AS2 (mov,%A0,%B1)); 
+         }
+       case 16:
+         {
+           int reg0 = true_regnum (operands[0]);
+           int reg1 = true_regnum (operands[1]);
+           *len=4;
+           if (reg0 <= reg1 + 1)
+             return (AS2 (mov,%A0,%C1) CR_TAB
+                     AS2 (mov,%B0,%D1) CR_TAB
+                     AS1 (clr,%C0)     CR_TAB
+                     AS1 (clr,%D0));
+           else if (reg0 == reg1 + 2)
+             return *len = 2, (AS1 (clr,%C0)     CR_TAB
+                               AS1 (clr,%D0));
+           else
+             return (AS2 (mov,%B0,%D1) CR_TAB
+                     AS2 (mov,%A0,%C1) CR_TAB
+                     AS1 (clr,%C0)     CR_TAB
+                     AS1 (clr,%D0));
+         }
+       case 24:
+         if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
+           return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
+                             AS1 (clr,%B0)     CR_TAB
+                             AS1 (clr,%C0)     CR_TAB
+                             AS1 (clr,%D0));
+         else
+           return *len = 3, (AS1 (clr,%B0)     CR_TAB
+                             AS1 (clr,%C0)     CR_TAB
+                             AS1 (clr,%D0));
+       }
+    }
+  if (len)
+    *len = 6;
+  out_shift_with_cnt (AS1 (lsr,%D0) CR_TAB
+                     AS1 (ror,%C0) CR_TAB
+                     AS1 (ror,%B0) CR_TAB
+                     AS1 (ror,%A0) CR_TAB
+                     AS1 (dec,%3) CR_TAB
+                     AS1 (brne,_PC_-12),
+                     insn, operands, len);
+  return "";
+}
+
+/* Modifies the length assigned to instruction INSN
+ LEN is the initially computed length of the insn.  */
+
+int
+adjust_insn_length (insn,len)
+     rtx insn;
+     int len;
+{
+  rtx patt = PATTERN (insn);
+  rtx set;
+  if (GET_CODE (patt) == SET)
+    {
+      rtx op[10];
+      op[1] = SET_SRC (patt);
+      op[0] = SET_DEST (patt);
+      if (REG_P (op[0]) && GET_CODE (op[1]) == MEM)
+        {
+         if (CONSTANT_ADDRESS_P (XEXP (op[1],0)))
+           switch (GET_MODE (op[0]))
+             {
+             case QImode: len = 2; break;
+             case HImode: len = 4; break;
+             case SImode:
+             case SFmode: len = 8; break;
+             default: break; 
+             }
+         else
+           switch (GET_MODE (op[0]))
+             {
+             case QImode: out_movqi_r_mr (insn,op,&len); break;
+             case HImode: out_movhi_r_mr (insn,op,&len); break;
+             case SImode:
+             case SFmode: out_movsi_r_mr (insn,op,&len); break;
+             default: break;
+             }
+        }
+      else if ((REG_P (op[1]) || const0_rtx == op[1])
+              && GET_CODE (op[0]) == MEM)
+        {
+         if (CONSTANT_ADDRESS_P (XEXP (op[0],0)))
+           switch (GET_MODE (op[0]))
+             {
+             case QImode: len = 2; break;
+             case HImode: len = 4; break;
+             case SImode:
+             case SFmode: len = 8; break;
+             default: break;
+             }
+         else if (GET_CODE (XEXP (op[0],0)) != POST_DEC)
+           switch (GET_MODE (op[0]))
+             {
+             case QImode: out_movqi_mr_r (insn,op,&len); break;
+             case HImode: out_movhi_mr_r (insn,op,&len); break;
+             case SImode:
+             case SFmode: out_movsi_mr_r (insn,op,&len); break;
+             default: break;
+             }
+        }
+      else if (op[0] == cc0_rtx && REG_P (op[1]))
+       {
+         switch (GET_MODE (op[1]))
+           {
+           case HImode: out_tsthi (insn,&len); break;
+           case SImode: out_tstsi (insn,&len); break;
+           default: break;
+           }
+       }
+      else if (GET_CODE (op[1]) == AND)
+       {
+         if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
+           {
+             HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
+             if (GET_MODE (op[1]) == SImode)
+               len = (((mask & 0xff) != 0xff)
+                      + ((mask & 0xff00) != 0xff00)
+                      + ((mask & 0xff0000UL) != 0xff0000UL)
+                      + ((mask & 0xff000000UL) != 0xff000000UL));
+             else if (GET_MODE (op[1]) == HImode)
+               len = (((mask & 0xff) != 0xff)
+                      + ((mask & 0xff00) != 0xff00));
+           }
+       }
+      else if (GET_CODE (op[1]) == IOR)
+       {
+         if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
+           {
+             HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
+             if (GET_MODE (op[1]) == SImode)
+               len = (((mask & 0xff) == 0)
+                      + ((mask & 0xff00) == 0)
+                      + ((mask & 0xff0000UL) == 0)
+                      + ((mask & 0xff000000UL) ==0));
+             else if (GET_MODE (op[1]) == HImode)
+               len = (((mask & 0xff) == 0)
+                      + ((mask & 0xff00) == 0));
+           }
+       }
+    }
+  set = single_set (insn);
+  if (set)
+    {
+      rtx op[10];
+      op[1] = SET_SRC (set);
+      op[0] = SET_DEST (set);
+      if (GET_CODE (op[1]) == ASHIFT
+         || GET_CODE (op[1]) == ASHIFTRT
+         || GET_CODE (op[1]) == LSHIFTRT)
+       {
+         rtx ops[10];
+         ops[0] = op[0];
+         ops[1] = XEXP (op[1],0);
+         ops[2] = XEXP (op[1],1);
+         switch (GET_CODE (op[1]))
+           {
+           case ASHIFT:
+             switch (GET_MODE (op[0]))
+               {
+               case QImode: ashlqi3_out (insn,ops,&len); break;
+               case HImode: ashlhi3_out (insn,ops,&len); break;
+               case SImode: ashlsi3_out (insn,ops,&len); break;
+               default: break;
+               }
+             break;
+           case ASHIFTRT:
+             switch (GET_MODE (op[0]))
+               {
+               case QImode: ashrqi3_out (insn,ops,&len); break;
+               case HImode: ashrhi3_out (insn,ops,&len); break;
+               case SImode: ashrsi3_out (insn,ops,&len); break;
+               default: break;
+               }
+             break;
+           case LSHIFTRT:
+             switch (GET_MODE (op[0]))
+               {
+               case QImode: lshrqi3_out (insn,ops,&len); break;
+               case HImode: lshrhi3_out (insn,ops,&len); break;
+               case SImode: lshrsi3_out (insn,ops,&len); break;
+               default: break;
+               }
+             break;
+           default:
+             break;
+           }
+       }
+    }
+  return len;
+}
+
+/* Return non-zero if register REG dead after INSN */
+
+int
+reg_unused_after (insn, reg)
+     rtx insn;
+     rtx reg;
+{
+  return (0
+         /* In egcs 1.1.x dead_or_set_p give buggy result after reload 
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
+         || dead_or_set_p (insn,reg)
+#endif
+         */
+         
+         || (REG_P(reg) && _reg_unused_after (insn, reg)));
+}
+
+/* Return non-zero if REG is not used after INSN.
+   We assume REG is a reload reg, and therefore does
+   not live past labels.  It may live past calls or jumps though.  */
+
+int
+_reg_unused_after (insn, reg)
+     rtx insn;
+     rtx reg;
+{
+  enum rtx_code code;
+  rtx set;
+
+  /* If the reg is set by this instruction, then it is safe for our
+     case.  Disregard the case where this is a store to memory, since
+     we are checking a register used in the store address.  */
+  set = single_set (insn);
+  if (set && GET_CODE (SET_DEST (set)) != MEM
+      && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+    return 1;
+
+  while ((insn = NEXT_INSN (insn)))
+    {
+      code = GET_CODE (insn);
+
+#if 0
+      /* If this is a label that existed before reload, then the register
+        if dead here.  However, if this is a label added by reorg, then
+        the register may still be live here.  We can't tell the difference,
+        so we just ignore labels completely.  */
+      if (code == CODE_LABEL)
+       return 1;
+      /* else */
+#endif
+
+      if (code == JUMP_INSN)
+       return 0;
+
+      /* If this is a sequence, we must handle them all at once.
+        We could have for instance a call that sets the target register,
+        and a insn in a delay slot that uses the register.  In this case,
+        we must return 0.  */
+      else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+       {
+         int i;
+         int retval = 0;
+
+         for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+           {
+             rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
+             rtx set = single_set (this_insn);
+
+             if (GET_CODE (this_insn) == CALL_INSN)
+               code = CALL_INSN;
+             else if (GET_CODE (this_insn) == JUMP_INSN)
+               {
+                 if (INSN_ANNULLED_BRANCH_P (this_insn))
+                   return 0;
+                 code = JUMP_INSN;
+               }
+
+             if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+               return 0;
+             if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+               {
+                 if (GET_CODE (SET_DEST (set)) != MEM)
+                   retval = 1;
+                 else
+                   return 0;
+               }
+             if (set == 0
+                 && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
+               return 0;
+           }
+         if (retval == 1)
+           return 1;
+         else if (code == JUMP_INSN)
+           return 0;
+       }
+
+      if (code == CALL_INSN)
+       {
+         rtx tem;
+         for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
+           if (GET_CODE (XEXP (tem, 0)) == USE
+               && REG_P (XEXP (XEXP (tem, 0), 0))
+               && reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
+             return 0;
+         if (call_used_regs[REGNO (reg)]) 
+           return 1;
+       }
+
+      if (GET_RTX_CLASS (code) == 'i')
+       {
+         rtx set = single_set (insn);
+
+         if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
+           return 0;
+         if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+           return GET_CODE (SET_DEST (set)) != MEM;
+         if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+           return 0;
+       }
+    }
+  return 1;
+}
+
+/* Output rtx VALUE as .byte to file FILE */
+
+void
+asm_output_char(file,value)
+     FILE *file;
+     rtx value;
+{
+  fprintf (file, "\t.byte ");
+  output_addr_const (file, value);
+  fprintf (file, "\n");
+}
+
+
+/* Output VALUE as .byte to file FILE */
+
+void
+asm_output_byte (file,value)
+     FILE *file;
+     char value;
+{
+  fprintf (file, "\t.byte 0x%x\n",value & 0xff);
+}
+
+
+/* Output rtx VALUE as .word to file FILE */
+
+void
+asm_output_short (file, value)
+     FILE *file;
+     rtx value;
+{
+  if (SYMBOL_REF_FLAG (value) || GET_CODE (value) == LABEL_REF)
+    {
+      fprintf (file, "\t.word pm(");
+      output_addr_const (file, (value));
+      fprintf (file, ")\n");
+    }
+  else
+    {
+      fprintf (file, "\t.word ");
+      output_addr_const (file, (value));
+      fprintf (file, "\n");
+    }
+}
+
+
+/* Output real N to file FILE */
+
+void
+asm_output_float (file, n)
+     FILE *file;
+     REAL_VALUE_TYPE n;
+{
+  long val;
+  char dstr[100];
+  
+  REAL_VALUE_TO_TARGET_SINGLE (n, val);
+  REAL_VALUE_TO_DECIMAL (n, "%g", dstr);
+  fprintf (file, "\t.long 0x%08lx\t/* %s */\n",val, dstr);
+}
+
+/* Sets section name for declaration DECL */
+  
+void
+unique_section (decl, reloc)
+     tree decl;
+     int reloc ATTRIBUTE_UNUSED;
+{
+  int len;
+  char *name,*string;
+  char *prefix;
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  /* Strip off any encoding in name.  */
+  STRIP_NAME_ENCODING (name, name);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      if (flag_function_sections)
+       prefix = ".text.";
+      else
+       prefix = ".text";
+    }
+  else 
+    fatal ("Strange situation: unique section is not a FUNCTION_DECL");
+
+  if (flag_function_sections)
+    {
+      len = strlen (name) + strlen (prefix);
+      string = alloca (len + 1);
+      sprintf (string, "%s%s", prefix, name);
+      DECL_SECTION_NAME (decl) = build_string (len, string);
+    }
+}
+
+
+/* Output section name to file FILE */
+
+void
+asm_output_section_name(file, decl, name, reloc)
+     FILE *file;
+     tree decl ATTRIBUTE_UNUSED;
+     const char *name;
+     int reloc ATTRIBUTE_UNUSED;
+{
+  fprintf (file, ".section %s\n", name);
+}
+
+
+/* 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)
+   as well as more readable, especially for targets like the i386
+   (where the only alternative is to output character sequences as
+   comma separated lists of numbers).   */
+
+void
+gas_output_limited_string(file, str)
+     FILE * file ATTRIBUTE_UNUSED;
+     char * str;
+{
+  unsigned char *_limited_str = (unsigned char *) str;
+  unsigned ch;
+  fprintf (file, "\t%s\t\"", STRING_ASM_OP);
+  for (; (ch = *_limited_str); _limited_str++)
+    {
+      int escape;
+      switch (escape = ESCAPES[ch])
+       {
+       case 0:
+         putc (ch, file);
+         break;
+       case 1:
+         fprintf (file, "\\%03o", ch);
+         break;
+       default:
+         putc ('\\', file);
+         putc (escape, file);
+         break;
+       }
+    }
+  fprintf (file, "\"\n");
+}
+
+/* The routine used to output sequences of byte values.  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)
+   as well as more readable.  Note that if we find subparts of the
+   character sequence which end with NUL (and which are shorter than
+   STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING.  */
+
+void
+gas_output_ascii(file, str, length)
+     FILE * file;
+     char * str;
+     size_t length;
+{
+  unsigned char *_ascii_bytes = (unsigned char *) str;
+  unsigned char *limit = _ascii_bytes + length;
+  unsigned bytes_in_chunk = 0;
+  for (; _ascii_bytes < limit; _ascii_bytes++)
+    {
+      register unsigned char *p;
+      if (bytes_in_chunk >= 60)
+       {
+         fprintf (file, "\"\n");
+         bytes_in_chunk = 0;
+       }
+      for (p = _ascii_bytes; p < limit && *p != '\0'; p++)
+       continue;
+      if (p < limit && (p - _ascii_bytes) <= (signed)STRING_LIMIT)
+       {
+         if (bytes_in_chunk > 0)
+           {
+             fprintf (file, "\"\n");
+             bytes_in_chunk = 0;
+           }
+         gas_output_limited_string (file, _ascii_bytes);
+         _ascii_bytes = p;
+       }
+      else
+       {
+         int escape;
+         unsigned ch;
+         if (bytes_in_chunk == 0)
+           fprintf (file, "\t.ascii\t\"");
+         switch (escape = ESCAPES[ch = *_ascii_bytes])
+           {
+           case 0:
+             putc (ch, file);
+             bytes_in_chunk++;
+             break;
+           case 1:
+             fprintf (file, "\\%03o", ch);
+             bytes_in_chunk += 4;
+             break;
+           default:
+             putc ('\\', file);
+             putc (escape, file);
+             bytes_in_chunk += 2;
+             break;
+           }
+       }
+    }
+  if (bytes_in_chunk > 0)
+    fprintf (file, "\"\n");
+}
+
+/* Return value is nonzero if pseudos that have been
+   assigned to registers of class CLASS would likely be spilled
+   because registers of CLASS are needed for spill registers.  */
+
+enum reg_class
+class_likely_spilled_p(int c)
+{
+  return (c != ALL_REGS && c != ADDW_REGS);
+}
+
+/* Only `progmem' attribute valid for type.  */
+
+int
+valid_machine_type_attribute(type, attributes, identifier, args)
+     tree type ATTRIBUTE_UNUSED;
+     tree attributes ATTRIBUTE_UNUSED;
+     tree identifier;
+     tree args ATTRIBUTE_UNUSED;
+{
+  return is_attribute_p ("progmem", identifier);
+}
+
+/* If IDENTIFIER with arguments ARGS is a valid machine specific
+   attribute for DECL return 1.
+   Valid attributes:
+   progmem - put data to program memory;
+   signal - make a function to be hardware interrupt. After function
+   epilogue interrupts are disabled;
+   interrupt - make a function to be hardware interrupt. After function
+   epilogue interrupts are enabled;
+   naked     - don't generate function prologue/epilogue and `ret' command.  */
+
+int
+valid_machine_decl_attribute (decl, attributes, attr, args)
+     tree decl;
+     tree attributes ATTRIBUTE_UNUSED;
+     tree attr;
+     tree args ATTRIBUTE_UNUSED;
+{
+  if (is_attribute_p ("interrupt", attr)
+      || is_attribute_p ("signal", attr)
+      || is_attribute_p ("naked", attr))
+    return TREE_CODE (decl) == FUNCTION_DECL;
+
+  if (is_attribute_p ("progmem", attr)
+      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+    {
+      if (DECL_INITIAL (decl) == NULL_TREE)
+       {
+         warning ("Only initialized variables can be placed into "
+                  "program memory area.");
+         return 0;
+       }
+      return 1;
+    }
+  return 0;
+}
+
+
+/* Look for attribute `progmem' in DECL
+   founded - 1 otherwise 0 */
+
+int
+avr_progmem_p (decl)
+     tree decl;
+{
+  tree a;
+
+  if (TREE_CODE (decl) != VAR_DECL)
+    return 0;
+
+  if (NULL_TREE
+      != lookup_attribute ("progmem", DECL_MACHINE_ATTRIBUTES (decl)))
+    return 1;
+
+  a=decl;
+  do
+    a = TREE_TYPE(a);
+  while (TREE_CODE (a) == ARRAY_TYPE);
+
+  if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
+    return 1;
+  
+  return 0;
+}
+
+/* Encode section information about tree DECL */
+  
+void
+encode_section_info (decl)
+     tree decl;
+{
+  if ((TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+      && TREE_CODE (decl) == VAR_DECL
+      && avr_progmem_p (decl))
+    {
+      char * dsec = ".progmem.data";
+      DECL_SECTION_NAME (decl) = build_string (strlen (dsec), dsec);
+    }
+}   
+
+/* Outputs to the stdio stream FILE some
+   appropriate text to go at the start of an assembler file.  */
+
+void
+asm_file_start (file)
+     FILE *file;
+{
+  output_file_directive (file, main_input_filename);
+  fprintf (file, "\t.arch %s\n", avr_mcu_type->name);
+  fputs ("__SREG__ = 0x3f\n"
+        "__SP_H__ = 0x3e\n"
+        "__SP_L__ = 0x3d\n", file);
+  
+  if (avr_ram_end)
+    initial_stack = avr_ram_end;
+  else
+    {
+      static char buf[30];
+      initial_stack = buf;
+      sprintf (buf, "0x%x", avr_mcu_type->stack);
+    }
+  
+  fputs ("__tmp_reg__ = r0\n" 
+        "__zero_reg__ = r1\n"
+        "_PC_ = 2\n", file);
+  
+  commands_in_file = 0;
+  commands_in_prologues = 0;
+  commands_in_epilogues = 0;
+}
+
+/* Outputs to the stdio stream FILE some
+   appropriate text to go at the end of an assembler file.  */
+
+void
+asm_file_end (file)
+     FILE *file;
+{
+  fprintf (file,
+          "/* File %s: code %4d (%4d), prologues %3d, epilogues %3d */\n",
+          main_input_filename,
+          commands_in_file,
+          commands_in_file - commands_in_prologues - commands_in_epilogues,
+          commands_in_prologues, commands_in_epilogues);
+}
+
+/* Choose the order in which to allocate hard registers for
+   pseudo-registers local to a basic block.
+
+   Store the desired register order in the array `reg_alloc_order'.
+   Element 0 should be the register to allocate first; element 1, the
+   next register; and so on.  */
+
+void
+order_regs_for_local_alloc (void)
+{
+  unsigned int i;
+  int order_0[] = {
+    24,25,
+    18,19,
+    20,21,
+    22,23,
+    30,31,
+    26,27,
+    28,29,
+    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+    0,1,
+    32,33,34,35
+  };
+  int order_1[] = {
+    18,19,
+    20,21,
+    22,23,
+    24,25,
+    30,31,
+    26,27,
+    28,29,
+    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+    0,1,
+    32,33,34,35
+  };
+  int order_2[] = {
+    25,24,
+    23,22,
+    21,20,
+    19,18,
+    30,31,
+    26,27,
+    28,29,
+    17,16,
+    15,14,13,12,11,10,9,8,7,6,5,4,3,2,
+    1,0,
+    32,33,34,35
+  };
+  
+  int *order = (TARGET_ORDER_1 ? order_1 :
+               TARGET_ORDER_2 ? order_2 :
+               order_0);
+  for (i=0; i < sizeof (order_0) / sizeof (order_0[0]); ++i)
+      reg_alloc_order[i] = order[i];
+}
+
+/* Calculate the cost of X code of the expression in which it is contained,
+   found in OUTER_CODE */
+
+int
+default_rtx_costs (X, code, outer_code)
+     rtx X;
+     enum rtx_code code;
+     enum rtx_code outer_code;
+{
+  int cost=0;
+  switch (code)
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      cost = 2 * GET_MODE_SIZE (GET_MODE (X));
+      break;
+    case MEM:
+      if (outer_code != SET)
+       cost = 1;
+      if (GET_CODE (XEXP (X,0)) == SYMBOL_REF)
+       cost += 2 * GET_MODE_SIZE (GET_MODE (X));
+      else
+       cost += GET_MODE_SIZE (GET_MODE (X));
+      break;
+    case CONST_INT:
+      cost = 0;
+      break;
+    case SIGN_EXTEND:
+      if (outer_code == SET)
+       cost = GET_MODE_SIZE (GET_MODE (X));
+      else
+       cost = -GET_MODE_SIZE (GET_MODE (X));
+      break;
+    case ZERO_EXTEND:
+      if (outer_code == SET)
+       cost = GET_MODE_SIZE (GET_MODE (X));
+      else
+       cost = -1;
+      break;
+    case PLUS:
+    case MINUS:
+      if (outer_code == SET)
+       {
+         if (X == stack_pointer_rtx)
+           cost = -10;
+         else if (GET_CODE (XEXP (X,1)) == CONST_INT)
+           cost = (INTVAL (XEXP (X,1)) <= 63 ? 1 :
+                    GET_MODE_SIZE (GET_MODE (X)));
+         else
+           cost = GET_MODE_SIZE (GET_MODE (X));
+       }
+      break;
+    case COMPARE:
+      if (GET_CODE (XEXP (X,1)) == CONST_INT)
+       cost = GET_MODE_SIZE (GET_MODE (XEXP (X,0)));
+      break;
+    default:
+      break;
+    }
+  return cost;
+}
+
+/* Calculate the cost of a memory address */
+
+int
+address_cost (rtx x)
+{
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x,1)) == CONST_INT
+      && (REG_P (XEXP (x,0)) || GET_CODE (XEXP (x,0)) == SUBREG)
+      && INTVAL (XEXP (x,1)) >= 61)
+    return 18;
+  if (CONSTANT_ADDRESS_P (x))
+    return 4;
+  return 4;
+}
+
+/*  EXTRA_CONSTRAINT helper */
+
+int
+extra_constraint (x,c)
+     rtx x;
+     char c;
+{
+  if (c == 'Q'
+      && GET_CODE (x) == MEM
+      && GET_CODE (XEXP (x,0)) == PLUS)
+    {
+         if (TARGET_ALL_DEBUG)
+           {
+             fprintf (stderr, ("extra_constraint:\n"
+                               "reload_completed: %d\n"
+                               "reload_in_progress: %d\n"),
+                      reload_completed, reload_in_progress);
+             debug_rtx (x);
+           }
+      if (GET_CODE (x) == MEM
+         && GET_CODE (XEXP (x,0)) == PLUS
+         && REG_P (XEXP (XEXP (x,0), 0))
+         && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
+         && (INTVAL (XEXP (XEXP (x,0), 1))
+             <= (64 - GET_MODE_SIZE (GET_MODE (x)))))
+       {
+         rtx xx = XEXP (XEXP (x,0), 0);
+         int regno = REGNO (xx);
+         if (TARGET_ALL_DEBUG)
+           {
+             fprintf (stderr, ("extra_constraint:\n"
+                               "reload_completed: %d\n"
+                               "reload_in_progress: %d\n"),
+                      reload_completed, reload_in_progress);
+             debug_rtx (x);
+           }
+         if (regno >= FIRST_PSEUDO_REGISTER)
+           return 1;           /* allocate pseudos */
+         else if (regno == REG_Z || regno == REG_Y)
+           return 1;           /* strictly check */
+         else if (xx == frame_pointer_rtx
+                  || xx == arg_pointer_rtx)
+           return 1;           /* XXX frame & arg pointer checks */
+       }
+    }
+  return 0;
+}
+
+/* Convert condition code CONDITION to the valid AVR condition code */
+
+RTX_CODE
+avr_normalize_condition (condition)
+     RTX_CODE condition;
+{
+  switch (condition)
+    {
+    case GT:
+      return GE;
+    case GTU:
+      return GEU;
+    case LE:
+      return LT;
+    case LEU:
+      return LTU;
+    default:
+      fatal ("Wrong condition: %s", GET_RTX_NAME (condition));
+    }
+}
+
+/* This fnction optimizes conditional jumps */
+
+void
+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)
+         || !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
+         && SET_DEST (pattern) == cc0_rtx
+         && compare_diff_p (insn))
+       {
+         if (GET_CODE (SET_SRC (pattern)) == COMPARE)
+           {
+             /* Now we work under compare insn */
+             
+             pattern = SET_SRC (pattern);
+             if (true_regnum (XEXP (pattern,0)) >= 0
+                 && true_regnum (XEXP (pattern,1)) >= 0 )
+               {
+                 rtx x = XEXP (pattern,0);
+                 rtx next = next_real_insn (insn);
+                 rtx pat = PATTERN (next);
+                 rtx src = SET_SRC (pat);
+                 rtx t = XEXP (src,0);
+                 PUT_CODE (t, swap_condition (GET_CODE (t)));
+                 XEXP (pattern,0) = XEXP (pattern,1);
+                 XEXP (pattern,1) = x;
+                 INSN_CODE (next) = -1;
+               }
+             else if (true_regnum (XEXP (pattern,0)) >= 0
+                      && GET_CODE (XEXP (pattern,1)) == CONST_INT)
+               {
+                 rtx x = XEXP (pattern,1);
+                 rtx next = next_real_insn (insn);
+                 rtx pat = PATTERN (next);
+                 rtx src = SET_SRC (pat);
+                 rtx t = XEXP (src,0);
+
+                 if (avr_simplify_comparision_p (GET_MODE (XEXP (pattern,0)),
+                                                 GET_CODE (t), x))
+                   {
+                     XEXP (pattern,1) = GEN_INT (INTVAL (x)+1);
+                     PUT_CODE (t, avr_normalize_condition (GET_CODE (t)));
+                     INSN_CODE (next) = -1;
+                     INSN_CODE (insn) = -1;
+                   }
+               }
+           }
+         else if (true_regnum (SET_SRC (pattern)) >= 0)
+           {
+             /* This is a tst insn */
+             rtx next = next_real_insn (insn);
+             rtx pat = PATTERN (next);
+             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;
+                 }
+           }
+       }
+    }
+}
+
+/* Returns register number for function return value.*/
+
+int
+avr_ret_register (void)
+{
+  return 24;
+}
+
+/* Ceate an RTX representing the place where a
+   library function returns a value of mode MODE.  */
+
+rtx
+avr_libcall_value (mode)
+     enum machine_mode mode;
+{
+  int offs = GET_MODE_SIZE (mode);
+  if (offs < 2)
+    offs = 2;
+  return gen_rtx (REG, mode, RET_REGISTER + 2 - offs);
+}
+
+/* Create an RTX representing the place where a
+   function returns a value of data type VALTYPE.  */
+
+rtx
+avr_function_value (type,func)
+     tree type;
+     tree func ATTRIBUTE_UNUSED;
+{
+  int offs;
+  if (TYPE_MODE (type) != BLKmode)
+    return avr_libcall_value (TYPE_MODE (type));
+  
+  offs = int_size_in_bytes (type);
+  if (offs < 2)
+    offs = 2;
+  if (offs > 2 && offs < GET_MODE_SIZE (SImode))
+    offs = GET_MODE_SIZE (SImode);
+  else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
+    offs = GET_MODE_SIZE (DImode);
+  
+  return gen_rtx (REG, BLKmode, RET_REGISTER + 2 - offs);
+}
+
+/* Returns non-zero if number MASK have only one setted bit */
+
+int
+mask_one_bit_p (mask)
+     HOST_WIDE_INT mask;
+{
+  int i;
+  unsigned HOST_WIDE_INT n=mask;
+  for (i = 0; i < 32; ++i)
+    {
+      if (n & 0x80000000UL)
+       {
+         if (n & 0x7fffffffUL)
+           return 0;
+         else
+           return 32-i;
+       }
+      n<<=1;
+    }
+  return 0; 
+}
+
+
+/* Places additional restrictions on the register class to
+   use when it is necessary to copy value X into a register
+   in class CLASS.  */
+
+enum reg_class
+preferred_reload_class(x,class)
+     rtx x;
+     enum reg_class class;
+{
+  if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0)
+    return class;
+  if (CONSTANT_P (x) && (class == NO_LD_REGS
+                        || class == ALL_REGS
+                        || class == GENERAL_REGS))
+    {
+      return LD_REGS;
+    }
+  return class;
+}
+
+void
+debug_hard_reg_set (HARD_REG_SET set)
+{
+  int i;
+  for (i=0; i < FIRST_PSEUDO_REGISTER; ++i)
+    {
+      if (TEST_HARD_REG_BIT (set, i))
+       {
+         fprintf (stderr, "r%-2d ", i);
+       }
+    }
+  fprintf (stderr, "\n");
+}
+            
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
new file mode 100644 (file)
index 0000000..270ae1f
--- /dev/null
@@ -0,0 +1,3206 @@
+/* Definitions of target machine for GNU compiler,
+   for ATMEL AVR at90s8515, ATmega103/103L, ATmega603/603L microcontrollers.
+
+   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Denis Chertykov (denisc@overta.ru)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#define CPP_PREDEFINES "-DAVR"
+/* Define this to be a string constant containing `-D' options to
+   define the predefined macros that identify this machine and system.
+   These macros will be predefined unless the `-ansi' option is
+   specified.
+
+   In addition, a parallel set of macros are predefined, whose names
+   are made by appending `__' at the beginning and at the end.  These
+   `__' macros are permitted by the ANSI standard, so they are
+   predefined regardless of whether `-ansi' is specified.
+
+   For example, on the Sun, one can use the following value:
+
+   "-Dmc68000 -Dsun -Dunix"
+
+   The result is to define the macros `__mc68000__', `__sun__' and
+   `__unix__' unconditionally, and the macros `mc68000', `sun' and
+   `unix' provided `-ansi' is not specified.  */
+
+
+/* This declaration should be present. */
+extern int target_flags;
+
+#define TARGET_ORDER_1         (target_flags &  0x1000)
+#define TARGET_ORDER_2         (target_flags &  0x4000)
+#define TARGET_INT8            (target_flags & 0x10000)
+#define TARGET_NO_INTERRUPTS   (target_flags & 0x20000)
+#define TARGET_INSN_SIZE_DUMP  (target_flags &  0x2000)
+#define TARGET_CALL_PROLOGUES  (target_flags & 0x40000)
+
+/* Dump each assembler insn's rtl into the output file.
+   This is for debugging the compiler itself.  */
+
+#define TARGET_RTL_DUMP                (target_flags &   0x010)
+#define TARGET_ALL_DEBUG       (target_flags &   0xfe0)
+
+/* `TARGET_...'
+   This series of macros is to allow compiler command arguments to
+   enable or disable the use of optional features of the target
+   machine.  For example, one machine description serves both the
+   68000 and the 68020; a command argument tells the compiler whether
+   it should use 68020-only instructions or not.  This command
+   argument works by means of a macro `TARGET_68020' that tests a bit
+   in `target_flags'.
+
+   Define a macro `TARGET_FEATURENAME' for each such option.  Its
+   definition should test a bit in `target_flags'; for example:
+
+   #define TARGET_68020 (target_flags & 1)
+
+   One place where these macros are used is in the
+   condition-expressions of instruction patterns.  Note how
+   `TARGET_68020' appears frequently in the 68000 machine description
+   file, `m68k.md'.  Another place they are used is in the
+   definitions of the other macros in the `MACHINE.h' file.  */
+
+
+
+#define TARGET_SWITCHES {                                              \
+  {"order1",0x1000, NULL},                                             \
+  {"order2",0x4000, NULL},                                             \
+  {"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"},                 \
+  {"rtl",0x10, NULL},                                                  \
+  {"size",0x2000,"Output instruction size's to the asm file"},         \
+  {"deb",0xfe0, NULL},                                                 \
+  {"",0, NULL}}
+/* This macro defines names of command options to set and clear bits
+   in `target_flags'.  Its definition is an initializer with a
+   subgrouping for each command option.
+
+   Each subgrouping contains a string constant, that defines the
+   option name, and a number, which contains the bits to set in
+   `target_flags'.  A negative number says to clear bits instead; the
+   negative of the number is which bits to clear.  The actual option
+   name is made by appending `-m' to the specified name.
+
+   One of the subgroupings should have a null string.  The number in
+   this grouping is the default value for `target_flags'.  Any target
+   options act starting with that value.
+
+   Here is an example which defines `-m68000' and `-m68020' with
+   opposite meanings, and picks the latter as the default:
+
+   #define TARGET_SWITCHES \
+   { { "68020", 1},      \
+   { "68000", -1},     \
+   { "", 1}}  */
+
+extern const char *avr_ram_end;
+extern const char *avr_mcu_name;
+
+struct mcu_type_s {
+  char * name;
+  int stack;
+  int mega;
+ };
+
+extern struct mcu_type_s *avr_mcu_type;
+#define AVR_MEGA (avr_mcu_type->mega)
+
+#define TARGET_OPTIONS {                                                     \
+ {"init-stack=",&avr_ram_end,"Specify the initial stack address" },          \
+ {"mcu=", &avr_mcu_name,                                                     \
+  "Specify the MCU name (at90s23xx,attiny22,at90s44xx,at90s85xx,atmega603,atmega103)"}}
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+   command options that have values.  Its definition is an
+   initializer with a subgrouping for each command option.
+
+   Each subgrouping contains a string constant, that defines the
+   fixed part of the option name, and the address of a variable.  The
+   variable, type `char *', is set to the variable part of the given
+   option if the fixed part matches.  The actual option name is made
+   by appending `-m' to the specified name.
+
+   Here is an example which defines `-mshort-data-NUMBER'.  If the
+   given option is `-mshort-data-512', the variable `m88k_short_data'
+   will be set to the string `"512"'.
+
+   extern char *m88k_short_data;
+   #define TARGET_OPTIONS \
+   { { "short-data-", &m88k_short_data } }  */
+
+#define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)");
+/* This macro is a C statement to print on `stderr' a string
+   describing the particular machine description choice.  Every
+   machine description should define `TARGET_VERSION'.  For example:
+
+   #ifdef MOTOROLA
+   #define TARGET_VERSION \
+   fprintf (stderr, " (68k, Motorola syntax)");
+   #else
+   #define TARGET_VERSION \
+   fprintf (stderr, " (68k, MIT syntax)");
+   #endif  */
+
+#define OVERRIDE_OPTIONS avr_override_options()
+/* `OVERRIDE_OPTIONS'
+   Sometimes certain combinations of command options do not make
+   sense on a particular target machine.  You can define a macro
+   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
+   defined, is executed once just after all the command options have
+   been parsed.
+
+   Don't use this macro to turn on various extra optimizations for
+   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
+
+#define CAN_DEBUG_WITHOUT_FP
+/* Define this macro if debugging can be performed even without a
+   frame pointer.  If this macro is defined, GNU CC will turn on the
+   `-fomit-frame-pointer' option whenever `-O' is specified.  */
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+#define BITS_BIG_ENDIAN 0
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+#define BYTES_BIG_ENDIAN 0
+
+/* Define this if most significant word of a multiword number is the lowest
+   numbered.  */
+#define WORDS_BIG_ENDIAN 0
+
+/* number of bits in an addressable storage unit */
+#define BITS_PER_UNIT 8
+
+/* Width in bits of a "word", which is the contents of a machine register.
+   Note that this is not necessarily the width of data type `int';  */
+#define BITS_PER_WORD 8
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD 1
+
+/* Width in bits of a pointer.
+   See also the macro `Pmode' defined below.  */
+#define POINTER_SIZE 16
+
+
+/* Maximum sized of reasonable data type
+   DImode or Dfmode ...  */
+#define MAX_FIXED_MODE_SIZE 32
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY 8
+
+/* Allocation boundary (in *bits*) for the code of a function. */
+#define FUNCTION_BOUNDARY 8
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY 8
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT 8
+
+
+/* Define this if move instructions will actually fail to work
+   when given unaligned data.  */
+#define STRICT_ALIGNMENT 0
+
+/* A C expression for the size in bits of the type `int' on the
+     target machine.  If you don't define this, the default is one word.  */
+#define INT_TYPE_SIZE (TARGET_INT8 ? 8 : 16)
+
+
+/* A C expression for the size in bits of the type `short' on the
+   target machine.  If you don't define this, the default is half a
+   word.  (If this would be less than one storage unit, it is rounded
+   up to one unit.)  */
+#define SHORT_TYPE_SIZE (INT_TYPE_SIZE == 8 ? INT_TYPE_SIZE : 16)
+
+/* A C expression for the size in bits of the type `long' on the
+   target machine.  If you don't define this, the default is one word.  */
+#define LONG_TYPE_SIZE (INT_TYPE_SIZE == 8 ? 16 : 32)
+
+#define MAX_LONG_TYPE_SIZE 32
+/* Maximum number for the size in bits of the type `long' on the
+   target machine.  If this is undefined, the default is
+   `LONG_TYPE_SIZE'.  Otherwise, it is the constant value that is the
+   largest value that `LONG_TYPE_SIZE' can have at run-time.  This is
+   used in `cpp'.  */
+
+
+#define LONG_LONG_TYPE_SIZE 64
+/* A C expression for the size in bits of the type `long long' on the
+   target machine.  If you don't define this, the default is two
+   words.  If you want to support GNU Ada on your machine, the value
+   of macro must be at least 64.  */
+
+
+#define  CHAR_TYPE_SIZE 8
+/* A C expression for the size in bits of the type `char' on the
+   target machine.  If you don't define this, the default is one
+   quarter of a word.  (If this would be less than one storage unit,
+   it is rounded up to one unit.)  */
+
+#define FLOAT_TYPE_SIZE 32
+/* A C expression for the size in bits of the type `float' on the
+   target machine.  If you don't define this, the default is one word.  */
+
+#define DOUBLE_TYPE_SIZE 32
+/* A C expression for the size in bits of the type `double' on the
+   target machine.  If you don't define this, the default is two
+   words. */
+
+
+#define LONG_DOUBLE_TYPE_SIZE 32
+/* A C expression for the size in bits of the type `long double' on
+   the target machine.  If you don't define this, the default is two
+   words.  */
+
+#define DEFAULT_SIGNED_CHAR 1
+/* An expression whose value is 1 or 0, according to whether the type
+   `char' should be signed or unsigned by default.  The user can
+   always override this default with the options `-fsigned-char' and
+   `-funsigned-char'.  */
+
+/* `DEFAULT_SHORT_ENUMS'
+   A C expression to determine whether to give an `enum' type only as
+   many bytes as it takes to represent the range of possible values
+   of that type.  A nonzero value means to do that; a zero value
+   means all `enum' types should be allocated like `int'.
+
+   If you don't define the macro, the default is 0.  */
+
+#define SIZE_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" : "unsigned int")
+/* A C expression for a string describing the name of the data type
+   to use for size values.  The typedef name `size_t' is defined
+   using the contents of the string.
+   
+   The string can contain more than one keyword.  If so, separate
+   them with spaces, and write first any length keyword, then
+   `unsigned' if appropriate, and finally `int'.  The string must
+   exactly match one of the data type names defined in the function
+   `init_decl_processing' in the file `c-decl.c'.  You may not omit
+   `int' or change the order--that would cause the compiler to crash
+   on startup.
+   
+   If you don't define this macro, the default is `"long unsigned
+   int"'.  */
+
+#define PTRDIFF_TYPE (INT_TYPE_SIZE == 8 ? "long unsigned int" :"unsigned int")
+/* A C expression for a string describing the name of the data type
+   to use for the result of subtracting two pointers.  The typedef
+   name `ptrdiff_t' is defined using the contents of the string.  See
+   `SIZE_TYPE' above for more information.
+   
+   If you don't define this macro, the default is `"long int"'.  */
+
+
+#define WCHAR_TYPE_SIZE 16
+/* A C expression for the size in bits of the data type for wide
+   characters.  This is used in `cpp', which cannot make use of
+   `WCHAR_TYPE'.  */
+
+#define FIRST_PSEUDO_REGISTER 36
+/* Number of hardware registers known to the compiler.  They receive
+   numbers 0 through `FIRST_PSEUDO_REGISTER-1'; thus, the first
+   pseudo register's number really is assigned the number
+   `FIRST_PSEUDO_REGISTER'.  */
+
+#define FIXED_REGISTERS {\
+  1,1,/* r0 r1 */\
+  0,0,/* r2 r3 */\
+  0,0,/* r4 r5 */\
+  0,0,/* r6 r7 */\
+  0,0,/* r8 r9 */\
+  0,0,/* r10 r11 */\
+  0,0,/* r12 r13 */\
+  0,0,/* r14 r15 */\
+  0,0,/* r16 r17 */\
+  0,0,/* r18 r19 */\
+  0,0,/* r20 r21 */\
+  0,0,/* r22 r23 */\
+  0,0,/* r24 r25 */\
+  0,0,/* r26 r27 */\
+  0,0,/* r28 r29 */\
+  0,0,/* r30 r31 */\
+  1,1,/*  STACK */\
+  1,1 /* arg pointer */  }
+/* An initializer that says which registers are used for fixed
+   purposes all throughout the compiled code and are therefore not
+   available for general allocation.  These would include the stack
+   pointer, the frame pointer (except on machines where that can be
+   used as a general register when no frame pointer is needed), the
+   program counter on machines where that is considered one of the
+   addressable registers, and any other numbered register with a
+   standard use.
+
+   This information is expressed as a sequence of numbers, separated
+   by commas and surrounded by braces.  The Nth number is 1 if
+   register N is fixed, 0 otherwise.
+
+   The table initialized from this macro, and the table initialized by
+   the following one, may be overridden at run time either
+   automatically, by the actions of the macro
+   `CONDITIONAL_REGISTER_USAGE', or by the user with the command
+   options `-ffixed-REG', `-fcall-used-REG' and `-fcall-saved-REG'.  */
+
+#define CALL_USED_REGISTERS {                  \
+  1,1,/* r0 r1 */                              \
+    0,0,/* r2 r3 */                            \
+    0,0,/* r4 r5 */                            \
+    0,0,/* r6 r7 */                            \
+    0,0,/* r8 r9 */                            \
+    0,0,/* r10 r11 */                          \
+    0,0,/* r12 r13 */                          \
+    0,0,/* r14 r15 */                          \
+    0,0,/* r16 r17 */                          \
+    1,1,/* r18 r19 */                          \
+    1,1,/* r20 r21 */                          \
+    1,1,/* r22 r23 */                          \
+    1,1,/* r24 r25 */                          \
+    1,1,/* r26 r27 */                          \
+    0,0,/* r28 r29 */                          \
+    1,1,/* r30 r31 */                          \
+    1,1,/*  STACK */                           \
+    1,1 /* arg pointer */  }
+/* Like `FIXED_REGISTERS' but has 1 for each register that is
+   clobbered (in general) by function calls as well as for fixed
+   registers.  This macro therefore identifies the registers that are
+   not available for general allocation of values that must live
+   across function calls.
+
+   If a register has 0 in `CALL_USED_REGISTERS', the compiler
+   automatically saves it on function entry and restores it on
+   function exit, if the register is used within the function.  */
+
+#define NON_SAVING_SETJMP 0
+/* If this macro is defined and has a nonzero value, it means that
+   `setjmp' and related functions fail to save the registers, or that
+   `longjmp' fails to restore them.  To compensate, the compiler
+   avoids putting variables in registers in functions that use
+   `setjmp'.  */
+
+#define REG_ALLOC_ORDER {                      \
+    24,25,                                     \
+    18,19,                                     \
+    20,21,                                     \
+    22,23,                                     \
+    30,31,                                     \
+    26,27,                                     \
+    28,29,                                     \
+    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,   \
+    0,1,                                       \
+    32,33,34,35                                        \
+    }
+/* If defined, an initializer for a vector of integers, containing the
+   numbers of hard registers in the order in which GNU CC should
+   prefer to use them (from most preferred to least).
+   
+   If this macro is not defined, registers are used lowest numbered
+   first (all else being equal).
+   
+   One use of this macro is on machines where the highest numbered
+   registers must always be saved and the save-multiple-registers
+   instruction supports only sequences of consetionve registers.  On
+   such machines, define `REG_ALLOC_ORDER' to be an initializer that
+   lists the highest numbered allocatable register first. */
+
+#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc ()
+/* ORDER_REGS_FOR_LOCAL_ALLOC'
+   A C statement (sans semicolon) to choose the order in which to
+   allocate hard registers for pseudo-registers local to a basic
+   block.
+
+   Store the desired register order in the array `reg_alloc_order'.
+   Element 0 should be the register to allocate first; element 1, the
+   next register; and so on.
+
+   The macro body should not assume anything about the contents of
+   `reg_alloc_order' before execution of the macro.
+
+   On most machines, it is not necessary to define this macro.  */
+
+
+#define HARD_REGNO_NREGS(REGNO, MODE) ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* A C expression for the number of consecutive hard registers,
+   starting at register number REGNO, required to hold a value of mode
+   MODE.
+
+   On a machine where all registers are exactly one word, a suitable
+   definition of this macro is
+
+   #define HARD_REGNO_NREGS(REGNO, MODE)            \
+   ((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)
+/* 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
+   registers are equivalent, a suitable definition is
+
+   #define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+   It is not necessary for this macro to check for the numbers of
+   fixed registers, because the allocation mechanism considers them
+   to be always occupied.
+
+   On some machines, double-precision values must be kept in even/odd
+   register pairs.  The way to implement that is to define this macro
+   to reject odd register numbers for such modes.
+
+   The minimum requirement for a mode to be OK in a register is that
+   the `movMODE' instruction pattern support moves between the
+   register and any other hard register for which the mode is OK; and
+   that moving a value into the register and back out not alter it.
+
+   Since the same instruction used to move `SImode' will work for all
+   narrower integer modes, it is not necessary on any machine for
+   `HARD_REGNO_MODE_OK' to distinguish between these modes, provided
+   you define patterns `movhi', etc., to take advantage of this.  This
+   is useful because of the interaction between `HARD_REGNO_MODE_OK'
+   and `MODES_TIEABLE_P'; it is very desirable for all integer modes
+   to be tieable.
+
+   Many machines have special registers for floating point arithmetic.
+   Often people assume that floating point machine modes are allowed
+   only in floating point registers.  This is not true.  Any
+   registers that can hold integers can safely *hold* a floating
+   point machine mode, whether or not floating arithmetic can be done
+   on it in those registers.  Integer move instructions can be used
+   to move the values.
+
+   On some machines, though, the converse is true: fixed-point machine
+   modes may not go in floating registers.  This is true if the
+   floating registers normalize any value stored in them, because
+   storing a non-floating value there would garble it.  In this case,
+   `HARD_REGNO_MODE_OK' should reject fixed-point machine modes in
+   floating registers.  But if the floating registers do not
+   automatically normalize, if you can store any bit pattern in one
+   and retrieve it unchanged without a trap, then any machine mode
+   may go in a floating register, so you can define this macro to say
+   so.
+
+   The primary significance of special floating registers is rather
+   that they are the registers acceptable in floating point arithmetic
+   instructions.  However, this is of no concern to
+   `HARD_REGNO_MODE_OK'.  You handle it by writing the proper
+   constraints for those instructions.
+
+   On some machines, the floating registers are especially slow to
+   access, so that it is better to store a value in a stack frame
+   than in such a register if floating point arithmetic is not being
+   done.  As long as the floating registers are not in class
+   `GENERAL_REGS', they will not be used unless some pattern's
+   constraint asks for one.  */
+
+#define MODES_TIEABLE_P(MODE1, MODE2) 0
+/* A C expression that is nonzero if it is desirable to choose
+   register allocation so as to avoid move instructions between a
+   value of mode MODE1 and a value of mode MODE2.
+
+   If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R,
+   MODE2)' are ever different for any R, then `MODES_TIEABLE_P (MODE1,
+   MODE2)' must be zero.  */
+
+enum reg_class {
+  NO_REGS,
+  R0_REG,                      /* r0 */
+  POINTER_X_REGS,              /* r26 - r27 */
+  POINTER_Y_REGS,              /* r28 - r29 */
+  POINTER_Z_REGS,              /* r30 - r31 */
+  STACK_REG,                   /* STACK */
+  BASE_POINTER_REGS,           /* r28 - r31 */
+  POINTER_REGS,                        /* r26 - r31 */
+  ADDW_REGS,                   /* r24 - r31 */
+  SIMPLE_LD_REGS,              /* r16 - r23 */
+  LD_REGS,                     /* r16 - r31 */
+  NO_LD_REGS,                  /* r0 - r15 */
+  GENERAL_REGS,                        /* r0 - r31 */
+  ALL_REGS, LIM_REG_CLASSES
+};
+/* An enumeral type that must be defined with all the register class
+   names as enumeral values.  `NO_REGS' must be first.  `ALL_REGS'
+   must be the last register class, followed by one more enumeral
+   value, `LIM_REG_CLASSES', which is not a register class but rather
+   tells how many classes there are.
+
+   Each register class has a number, which is the value of casting
+   the class name to type `int'.  The number serves as an index in
+   many of the tables described below.  */
+
+
+#define N_REG_CLASSES (int)LIM_REG_CLASSES
+/* The number of distinct register classes, defined as follows:
+
+   #define N_REG_CLASSES (int) LIM_REG_CLASSES  */
+
+#define REG_CLASS_NAMES {                                      \
+                "NO_REGS",                                     \
+                  "R0_REG",    /* r0 */                        \
+                  "POINTER_X_REGS", /* r26 - r27 */            \
+                  "POINTER_Y_REGS", /* r28 - r29 */            \
+                  "POINTER_Z_REGS", /* r30 - r31 */            \
+                  "STACK_REG", /* STACK */                     \
+                  "BASE_POINTER_REGS", /* r28 - r31 */         \
+                  "POINTER_REGS", /* r26 - r31 */              \
+                  "ADDW_REGS", /* r24 - r31 */                 \
+                   "SIMPLE_LD_REGS", /* r16 - r23 */            \
+                  "LD_REGS",   /* r16 - r31 */                 \
+                   "NO_LD_REGS", /* r0 - r15 */                 \
+                  "GENERAL_REGS", /* r0 - r31 */               \
+                  "ALL_REGS" }
+/* An initializer containing the names of the register classes as C
+   string constants.  These names are used in writing some of the
+   debugging dumps.  */
+
+#define REG_X 26
+#define REG_Y 28
+#define REG_Z 30
+#define REG_W 24
+
+#define REG_CLASS_CONTENTS {                                           \
+  {0x00000000,0x00000000},     /* NO_REGS */                           \
+  {0x00000001,0x00000000},     /* R0_REG */                            \
+  {3 << REG_X,0x00000000},      /* POINTER_X_REGS, r26 - r27 */                \
+  {3 << REG_Y,0x00000000},      /* POINTER_Y_REGS, r28 - r29 */                \
+  {3 << REG_Z,0x00000000},      /* POINTER_Z_REGS, r30 - r31 */                \
+  {0x00000000,0x00000003},     /* STACK_REG, STACK */                  \
+  {(3 << REG_Y) | (3 << REG_Z),                                                \
+     0x00000000},              /* BASE_POINTER_REGS, r28 - r31 */      \
+  {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z),                         \
+     0x00000000},              /* POINTER_REGS, r26 - r31 */           \
+  {(3 << REG_X) | (3 << REG_Y) | (3 << REG_Z) | (3 << REG_W),          \
+     0x00000000},              /* ADDW_REGS, r24 - r31 */              \
+  {0x00ff0000,0x00000000},     /* SIMPLE_LD_REGS r16 - r23 */          \
+  {(3 << REG_X)|(3 << REG_Y)|(3 << REG_Z)|(3 << REG_W)|(0xff << 16),   \
+     0x00000000},      /* LD_REGS, r16 - r31 */                        \
+  {0x0000ffff,0x00000000},     /* NO_LD_REGS  r0 - r15 */              \
+  {0xffffffffu,0x00000000},    /* GENERAL_REGS, r0 - r31 */            \
+  {0xffffffffu,0x00000003}     /* ALL_REGS */                          \
+}
+/* An initializer containing the contents of the register classes, as
+   integers which are bit masks.  The Nth integer specifies the
+   contents of class N.  The way the integer MASK is interpreted is
+   that register R is in the class if `MASK & (1 << R)' is 1.
+
+   When the machine has more than 32 registers, an integer does not
+   suffice.  Then the integers are replaced by sub-initializers,
+   braced groupings containing several integers.  Each
+   sub-initializer must be suitable as an initializer for the type
+   `HARD_REG_SET' which is defined in `hard-reg-set.h'.  */
+
+#define REGNO_REG_CLASS(R) avr_regno_reg_class(R)
+/* A C expression whose value is a register class containing hard
+   register REGNO.  In general there is more than one such class;
+   choose a class which is "minimal", meaning that no smaller class
+   also contains the register.  */
+
+#define BASE_REG_CLASS POINTER_REGS
+/* A macro whose definition is the name of the class to which a valid
+   base register must belong.  A base register is one used in an
+   address which is the register value plus a displacement.  */
+
+#define INDEX_REG_CLASS NO_REGS
+/* A macro whose definition is the name of the class to which a valid
+   index register must belong.  An index register is one used in an
+   address where its value is either multiplied by a scale factor or
+   added to another register (as well as added to a displacement).  */
+
+#define REG_CLASS_FROM_LETTER(C) avr_reg_class_from_letter(C)
+/* A C expression which defines the machine-dependent operand
+   constraint letters for register classes.  If CHAR is such a
+   letter, the value should be the register class corresponding to
+   it.  Otherwise, the value should be `NO_REGS'.  The register
+   letter `r', corresponding to class `GENERAL_REGS', will not be
+   passed to this macro; you do not need to handle it.  */
+
+#define REGNO_OK_FOR_BASE_P(r) (((r) < FIRST_PSEUDO_REGISTER           \
+                                && ((r) == REG_X                       \
+                                    || (r) == REG_Y                    \
+                                    || (r) == REG_Z                    \
+                                    || (r) == ARG_POINTER_REGNUM))     \
+                               || (reg_renumber                        \
+                                   && (reg_renumber[r] == REG_X        \
+                                       || reg_renumber[r] == REG_Y     \
+                                       || reg_renumber[r] == REG_Z     \
+                                       || (reg_renumber[r]             \
+                                           == ARG_POINTER_REGNUM))))
+/* A C expression which is nonzero if register number NUM is suitable
+   for use as a base register in operand addresses.  It may be either
+   a suitable hard register or a pseudo register that has been
+   allocated such a hard register.  */
+
+/* #define REGNO_MODE_OK_FOR_BASE_P(r, m) regno_mode_ok_for_base_p(r, m)
+   A C expression that is just like `REGNO_OK_FOR_BASE_P', except that
+   that expression may examine the mode of the memory reference in
+   MODE.  You should define this macro if the mode of the memory
+   reference affects whether a register may be used as a base
+   register.  If you define this macro, the compiler will use it
+   instead of `REGNO_OK_FOR_BASE_P'.  */
+
+#define REGNO_OK_FOR_INDEX_P(NUM) 0
+/* A C expression which is nonzero if register number NUM is suitable
+   for use as an index register in operand addresses.  It may be
+   either a suitable hard register or a pseudo register that has been
+   allocated such a hard register.
+
+   The difference between an index register and a base register is
+   that the index register may be scaled.  If an address involves the
+   sum of two registers, neither one of them scaled, then either one
+   may be labeled the "base" and the other the "index"; but whichever
+   labeling is used must fit the machine's constraints of which
+   registers may serve in each capacity.  The compiler will try both
+   labelings, looking for one that is valid, and will reload one or
+   both registers only if neither labeling works.  */
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) preferred_reload_class(X,CLASS)
+/* A C expression that places additional restrictions on the register
+   class to use when it is necessary to copy value X into a register
+   in class CLASS.  The value is a register class; perhaps CLASS, or
+   perhaps another, smaller class.  On many machines, the following
+   definition is safe:
+
+   #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
+
+   Sometimes returning a more restrictive class makes better code.
+   For example, on the 68000, when X is an integer constant that is
+   in range for a `moveq' instruction, the value of this macro is
+   always `DATA_REGS' as long as CLASS includes the data registers.
+   Requiring a data register guarantees that a `moveq' will be used.
+
+   If X is a `const_double', by returning `NO_REGS' you can force X
+   into a memory constant.  This is useful on certain machines where
+   immediate floating values cannot be loaded into certain kinds of
+   registers.  */
+/* `PREFERRED_OUTPUT_RELOAD_CLASS (X, CLASS)'
+   Like `PREFERRED_RELOAD_CLASS', but for output reloads instead of
+   input reloads.  If you don't define this macro, the default is to
+   use CLASS, unchanged.  */
+
+/* `LIMIT_RELOAD_CLASS (MODE, CLASS)'
+   A C expression that places additional restrictions on the register
+   class to use when it is necessary to be able to hold a value of
+   mode MODE in a reload register for which class CLASS would
+   ordinarily be used.
+
+   Unlike `PREFERRED_RELOAD_CLASS', this macro should be used when
+   there are certain modes that simply can't go in certain reload
+   classes.
+
+   The value is a register class; perhaps CLASS, or perhaps another,
+   smaller class.
+
+   Don't define this macro unless the target machine has limitations
+   which require the macro to do something nontrivial.  */
+
+/* SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X)
+   `SECONDARY_RELOAD_CLASS (CLASS, MODE, X)'
+   `SECONDARY_OUTPUT_RELOAD_CLASS (CLASS, MODE, X)'
+   Many machines have some registers that cannot be copied directly
+   to or from memory or even from other types of registers.  An
+   example is the `MQ' register, which on most machines, can only be
+   copied to or from general registers, but not memory.  Some
+   machines allow copying all registers to and from memory, but
+   require a scratch register for stores to some memory locations
+   (e.g., those with symbolic address on the RT, and those with
+   certain symbolic address on the Sparc when compiling PIC).  In
+   some cases, both an intermediate and a scratch register are
+   required.
+
+   You should define these macros to indicate to the reload phase
+   that it may need to allocate at least one register for a reload in
+   addition to the register to contain the data.  Specifically, if
+   copying X to a register CLASS in MODE requires an intermediate
+   register, you should define `SECONDARY_INPUT_RELOAD_CLASS' to
+   return the largest register class all of whose registers can be
+   used as intermediate registers or scratch registers.
+
+   If copying a register CLASS in MODE to X requires an intermediate
+   or scratch register, `SECONDARY_OUTPUT_RELOAD_CLASS' should be
+   defined to return the largest register class required.  If the
+   requirements for input and output reloads are the same, the macro
+   `SECONDARY_RELOAD_CLASS' should be used instead of defining both
+   macros identically.
+
+   The values returned by these macros are often `GENERAL_REGS'.
+   Return `NO_REGS' if no spare register is needed; i.e., if X can be
+   directly copied to or from a register of CLASS in MODE without
+   requiring a scratch register.  Do not define this macro if it
+   would always return `NO_REGS'.
+
+   If a scratch register is required (either with or without an
+   intermediate register), you should define patterns for
+   `reload_inM' or `reload_outM', as required (*note Standard
+   Names::..  These patterns, which will normally be implemented with
+   a `define_expand', should be similar to the `movM' patterns,
+   except that operand 2 is the scratch register.
+
+   Define constraints for the reload register and scratch register
+   that contain a single register class.  If the original reload
+   register (whose class is CLASS) can meet the constraint given in
+   the pattern, the value returned by these macros is used for the
+   class of the scratch register.  Otherwise, two additional reload
+   registers are required.  Their classes are obtained from the
+   constraints in the insn pattern.
+
+   X might be a pseudo-register or a `subreg' of a pseudo-register,
+   which could either be in a hard register or in memory.  Use
+   `true_regnum' to find out; it will return -1 if the pseudo is in
+   memory and the hard register number if it is in a register.
+
+   These macros should not be used in the case where a particular
+   class of registers can only be copied to memory and not to another
+   class of registers.  In that case, secondary reload registers are
+   not needed and would not be helpful.  Instead, a stack location
+   must be used to perform the copy and the `movM' pattern should use
+   memory as a intermediate storage.  This case often occurs between
+   floating-point and general registers.  */
+
+/* `SECONDARY_MEMORY_NEEDED (CLASS1, CLASS2, M)'
+   Certain machines have the property that some registers cannot be
+   copied to some other registers without using memory.  Define this
+   macro on those machines to be a C expression that is non-zero if
+   objects of mode M in registers of CLASS1 can only be copied to
+   registers of class CLASS2 by storing a register of CLASS1 into
+   memory and loading that memory location into a register of CLASS2.
+
+   Do not define this macro if its value would always be zero.
+
+   `SECONDARY_MEMORY_NEEDED_RTX (MODE)'
+   Normally when `SECONDARY_MEMORY_NEEDED' is defined, the compiler
+   allocates a stack slot for a memory location needed for register
+   copies.  If this macro is defined, the compiler instead uses the
+   memory location defined by this macro.
+
+   Do not define this macro if you do not define
+   `SECONDARY_MEMORY_NEEDED'.  */
+
+#define SMALL_REGISTER_CLASSES 1
+/* Normally the compiler avoids choosing registers that have been
+   explicitly mentioned in the rtl as spill registers (these
+   registers are normally those used to pass parameters and return
+   values).  However, some machines have so few registers of certain
+   classes that there would not be enough registers to use as spill
+   registers if this were done.
+
+   Define `SMALL_REGISTER_CLASSES' to be an expression with a non-zero
+   value on these machines.  When this macro has a non-zero value, the
+   compiler allows registers explicitly used in the rtl to be used as
+   spill registers but avoids extending the lifetime of these
+   registers.
+
+   It is always safe to define this macro with a non-zero value, but
+   if you unnecessarily define it, you will reduce the amount of
+   optimizations that can be performed in some cases.  If you do not
+   define this macro with a non-zero value when it is required, the
+   compiler will run out of spill registers and print a fatal error
+   message.  For most machines, you should not define this macro at
+   all.  */
+
+#define CLASS_LIKELY_SPILLED_P(c) class_likely_spilled_p(c)
+/* A C expression whose value is nonzero if pseudos that have been
+   assigned to registers of class CLASS would likely be spilled
+   because registers of CLASS are needed for spill registers.
+
+   The default value of this macro returns 1 if CLASS has exactly one
+   register and zero otherwise.  On most machines, this default
+   should be used.  Only define this macro to some other expression
+   if pseudo allocated by `local-alloc.c' end up in memory because
+   their hard registers were needed for spill registers.  If this
+   macro returns nonzero for those classes, those pseudos will only
+   be allocated by `global.c', which knows how to reallocate the
+   pseudo to another register.  If there would not be another
+   register available for reallocation, you should not change the
+   definition of this macro since the only effect of such a
+   definition would be to slow down register allocation.  */
+
+#define CLASS_MAX_NREGS(CLASS, MODE)   class_max_nregs (CLASS, MODE)
+/* A C expression for the maximum number of consecutive registers of
+   class CLASS needed to hold a value of mode MODE.
+
+   This is closely related to the macro `HARD_REGNO_NREGS'.  In fact,
+   the value of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be
+   the maximum value of `HARD_REGNO_NREGS (REGNO, MODE)' for all
+   REGNO values in the class CLASS.
+
+   This macro helps control the handling of multiple-word values in
+   the reload pass.  */
+
+#undef CLASS_CANNOT_CHANGE_SIZE
+/* `CLASS_CANNOT_CHANGE_SIZE'
+   If defined, a C expression for a class that contains registers
+   which the compiler must always access in a mode that is the same
+   size as the mode in which it loaded the register.
+
+   For the example, loading 32-bit integer or floating-point objects
+   into floating-point registers on the Alpha extends them to 64-bits.
+   Therefore loading a 64-bit object and then storing it as a 32-bit
+   object does not store the low-order 32-bits, as would be the case
+   for a normal register.  Therefore, `alpha.h' defines this macro as
+   `FLOAT_REGS'.
+
+   Three other special macros describe which operands fit which
+   constraint letters.  */
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C)                                \
+  ((C) == 'I' ? (VALUE) >= 0 && (VALUE) <= 63 :                        \
+   (C) == 'J' ? (VALUE) <= 0 && (VALUE) >= -63:                        \
+   (C) == 'K' ? (VALUE) == 2 :                                 \
+   (C) == 'L' ? (VALUE) == 0 :                                 \
+   (C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 0xff :              \
+   (C) == 'N' ? (VALUE) == -1:                                 \
+   (C) == 'O' ? (VALUE) == 8 || (VALUE) == 16 || (VALUE) == 24:        \
+   (C) == 'P' ? (VALUE) == 1 :                                 \
+   0)
+
+/* A C expression that defines the machine-dependent operand
+   constraint letters (`I', `J', `K', ... `P') that specify
+   particular ranges of integer values.  If C is one of those
+   letters, the expression should check that VALUE, an integer, is in
+   the appropriate range and return 1 if so, 0 otherwise.  If C is
+   not one of those letters, the value should be 0 regardless of
+   VALUE.  */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
+  ((C) == 'G' ? (VALUE) == CONST0_RTX (SFmode) \
+   : 0)
+/* `CONST_DOUBLE_OK_FOR_LETTER_P (VALUE, C)'
+   A C expression that defines the machine-dependent operand
+   constraint letters that specify particular ranges of
+   `const_double' values (`G' or `H').
+
+   If C is one of those letters, the expression should check that
+   VALUE, an RTX of code `const_double', is in the appropriate range
+   and return 1 if so, 0 otherwise.  If C is not one of those
+   letters, the value should be 0 regardless of VALUE.
+
+   `const_double' is used for all floating-point constants and for
+   `DImode' fixed-point constants.  A given letter can accept either
+   or both kinds of values.  It can use `GET_MODE' to distinguish
+   between these kinds.  */
+
+#define EXTRA_CONSTRAINT(x, c) extra_constraint(x, c)
+/* A C expression that defines the optional machine-dependent
+   constraint letters (``Q', `R', `S', `T', `U') that can'
+   be used to segregate specific types of operands, usually memory
+   references, for the target machine.  Normally this macro will not
+   be defined.  If it is required for a particular target machine, it
+   should return 1 if VALUE corresponds to the operand type
+   represented by the constraint letter C.  If C is not defined as an
+   extra constraint, the value returned should be 0 regardless of
+   VALUE.
+
+   For example, on the ROMP, load instructions cannot have their
+   output in r0 if the memory reference contains a symbolic address.
+   Constraint letter `Q' is defined as representing a memory address
+   that does *not* contain a symbolic address.  An alternative is
+   specified with a `Q' constraint on the input and `r' on the
+   output.  The next alternative specifies `m' on the input and a
+   register class that does not include r0 on the output.  */
+
+/*  This is an undocumented variable which describes
+    how GCC will push a data */
+#define STACK_PUSH_CODE POST_DEC
+
+#define STACK_GROWS_DOWNWARD
+/* Define this macro if pushing a word onto the stack moves the stack
+   pointer to a smaller address.
+
+   When we say, "define this macro if ...," it means that the
+   compiler checks this macro only with `#ifdef' so the precise
+   definition used does not matter.  */
+
+#define STARTING_FRAME_OFFSET 1
+/* Offset from the frame pointer to the first local variable slot to
+   be allocated.
+
+   If `FRAME_GROWS_DOWNWARD', find the next slot's offset by
+   subtracting the first slot's length from `STARTING_FRAME_OFFSET'.
+   Otherwise, it is found by adding the length of the first slot to
+   the value `STARTING_FRAME_OFFSET'.  */
+
+#define STACK_POINTER_OFFSET 1
+/* Offset from the stack pointer register to the first location at
+   which outgoing arguments are placed.  If not specified, the
+   default value of zero is used.  This is the proper value for most
+   machines.
+
+   If `ARGS_GROW_DOWNWARD', this is the offset to the location above
+   the first location at which outgoing arguments are placed.  */
+
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+/* Offset from the argument pointer register to the first argument's
+   address.  On some machines it may depend on the data type of the
+   function.
+
+   If `ARGS_GROW_DOWNWARD', this is the offset to the location above
+   the first argument's address.  */
+
+/* `STACK_DYNAMIC_OFFSET (FUNDECL)'
+   Offset from the stack pointer register to an item dynamically
+   allocated on the stack, e.g., by `alloca'.
+
+   The default value for this macro is `STACK_POINTER_OFFSET' plus the
+   length of the outgoing arguments.  The default is correct for most
+   machines.  See `function.c' for details.  */
+
+#define STACK_BOUNDARY 8
+/* Define this macro if there is a guaranteed alignment for the stack
+   pointer on this machine.  The definition is a C expression for the
+   desired alignment (measured in bits).  This value is used as a
+   default if PREFERRED_STACK_BOUNDARY is not defined.  */
+
+#define STACK_POINTER_REGNUM 32
+/* The register number of the stack pointer register, which must also
+   be a fixed register according to `FIXED_REGISTERS'.  On most
+   machines, the hardware determines which register this is.  */
+
+#define FRAME_POINTER_REGNUM REG_Y
+/* The register number of the frame pointer register, which is used to
+   access automatic variables in the stack frame.  On some machines,
+   the hardware determines which register this is.  On other
+   machines, you can choose any register you wish for this purpose.  */
+
+#define ARG_POINTER_REGNUM 34
+/* The register number of the arg pointer register, which is used to
+   access the function's argument list.  On some machines, this is
+   the same as the frame pointer register.  On some machines, the
+   hardware determines which register this is.  On other machines,
+   you can choose any register you wish for this purpose.  If this is
+   not the same register as the frame pointer register, then you must
+   mark it as a fixed register according to `FIXED_REGISTERS', or
+   arrange to be able to eliminate it (*note Elimination::.).  */
+
+#define STATIC_CHAIN_REGNUM 2
+/* Register numbers used for passing a function's static chain
+   pointer.  If register windows are used, the register number as
+   seen by the called function is `STATIC_CHAIN_INCOMING_REGNUM',
+   while the register number as seen by the calling function is
+   `STATIC_CHAIN_REGNUM'.  If these registers are the same,
+   `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
+
+   The static chain register need not be a fixed register.
+
+   If the static chain is passed in memory, these macros should not be
+   defined; instead, the next two macros should be defined.  */
+
+#define FRAME_POINTER_REQUIRED frame_pointer_required_p()
+/* A C expression which is nonzero if a function must have and use a
+   frame pointer.  This expression is evaluated  in the reload pass.
+   If its value is nonzero the function will have a frame pointer.
+
+   The expression can in principle examine the current function and
+   decide according to the facts, but on most machines the constant 0
+   or the constant 1 suffices.  Use 0 when the machine allows code to
+   be generated with no frame pointer, and doing so saves some time
+   or space.  Use 1 when there is no possible advantage to avoiding a
+   frame pointer.
+
+   In certain cases, the compiler does not know how to produce valid
+   code without a frame pointer.  The compiler recognizes those cases
+   and automatically gives the function a frame pointer regardless of
+   what `FRAME_POINTER_REQUIRED' says.  You don't need to worry about
+   them.
+
+   In a function that does not require a frame pointer, the frame
+   pointer register can be allocated for ordinary usage, unless you
+   mark it as a fixed register.  See `FIXED_REGISTERS' for more
+   information.  */
+
+#define ELIMINABLE_REGS {                                      \
+      {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},              \
+       {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}            \
+       ,{FRAME_POINTER_REGNUM+1,STACK_POINTER_REGNUM+1}}
+/* If defined, this macro specifies a table of register pairs used to
+   eliminate unneeded registers that point into the stack frame.  If
+   it is not defined, the only elimination attempted by the compiler
+   is to replace references to the frame pointer with references to
+   the stack pointer.
+
+   The definition of this macro is a list of structure
+   initializations, each of which specifies an original and
+   replacement register.
+
+   On some machines, the position of the argument pointer is not
+   known until the compilation is completed.  In such a case, a
+   separate hard register must be used for the argument pointer.
+   This register can be eliminated by replacing it with either the
+   frame pointer or the argument pointer, depending on whether or not
+   the frame pointer has been eliminated.
+
+   In this case, you might specify:
+   #define ELIMINABLE_REGS  \
+   {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+   {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+   {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+   Note that the elimination of the argument pointer with the stack
+   pointer is specified first since that is the preferred elimination.  */
+
+#define CAN_ELIMINATE(FROM, TO) (((FROM) == ARG_POINTER_REGNUM            \
+                                 && (TO) == FRAME_POINTER_REGNUM)         \
+                                || (((FROM) == FRAME_POINTER_REGNUM       \
+                                     || (FROM) == FRAME_POINTER_REGNUM+1) \
+                                    && ! FRAME_POINTER_REQUIRED           \
+                                    ))
+/* A C expression that returns non-zero if the compiler is allowed to
+   try to replace register number FROM-REG with register number
+   TO-REG.  This macro need only be defined if `ELIMINABLE_REGS' is
+   defined, and will usually be the constant 1, since most of the
+   cases preventing register elimination are things that the compiler
+   already knows about.  */
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                   \
+     OFFSET = initial_elimination_offset (FROM, TO)
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'.  It
+   specifies the initial difference between the specified pair of
+   registers.  This macro must be defined if `ELIMINABLE_REGS' is
+   defined.  */
+
+#define PUSH_ROUNDING(NPUSHED) (NPUSHED)
+/* A C expression that is the number of bytes actually pushed onto the
+   stack when an instruction attempts to push NPUSHED bytes.
+
+   If the target machine does not have a push instruction, do not
+   define this macro.  That directs GNU CC to use an alternate
+   strategy: to allocate the entire argument block and then store the
+   arguments into it.
+
+   On some machines, the definition
+
+   #define PUSH_ROUNDING(BYTES) (BYTES)
+
+   will suffice.  But on other machines, instructions that appear to
+   push one byte actually push two bytes in an attempt to maintain
+   alignment.  Then the definition should be
+
+   #define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1)  */
+
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACK_SIZE) 0
+/* A C expression that should indicate the number of bytes of its own
+   arguments that a function pops on returning, or 0 if the function
+   pops no arguments and the caller must therefore pop them all after
+   the function returns.
+
+   FUNDECL is a C variable whose value is a tree node that describes
+   the function in question.  Normally it is a node of type
+   `FUNCTION_DECL' that describes the declaration of the function.
+   From this you can obtain the DECL_MACHINE_ATTRIBUTES of the
+   function.
+
+   FUNTYPE is a C variable whose value is a tree node that describes
+   the function in question.  Normally it is a node of type
+   `FUNCTION_TYPE' that describes the data type of the function.
+   From this it is possible to obtain the data types of the value and
+   arguments (if known).
+
+   When a call to a library function is being considered, FUNDECL
+   will contain an identifier node for the library function.  Thus, if
+   you need to distinguish among various library functions, you can
+   do so by their names.  Note that "library function" in this
+   context means a function used to perform arithmetic, whose name is
+   known specially in the compiler and was not mentioned in the C
+   code being compiled.
+
+   STACK-SIZE is the number of bytes of arguments passed on the
+   stack.  If a variable number of bytes is passed, it is zero, and
+   argument popping will always be the responsibility of the calling
+   function.
+
+   On the Vax, all functions always pop their arguments, so the
+   definition of this macro is STACK-SIZE.  On the 68000, using the
+   standard calling convention, no functions pop their arguments, so
+   the value of the macro is always 0 in this case.  But an
+   alternative calling convention is available in which functions
+   that take a fixed number of arguments pop them but other functions
+   (such as `printf') pop nothing (the caller pops all).  When this
+   convention is in use, FUNTYPE is examined to determine whether a
+   function takes a fixed number of arguments.  */
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) (function_arg (&(CUM), MODE, TYPE, NAMED))
+/* A C expression that controls whether a function argument is passed
+   in a register, and which register.
+
+   The arguments are CUM, which summarizes all the previous
+   arguments; MODE, the machine mode of the argument; TYPE, the data
+   type of the argument as a tree node or 0 if that is not known
+   (which happens for C support library functions); and NAMED, which
+   is 1 for an ordinary argument and 0 for nameless arguments that
+   correspond to `...' in the called function's prototype.
+
+   The value of the expression is usually either a `reg' RTX for the
+   hard register in which to pass the argument, or zero to pass the
+   argument on the stack.
+
+   For machines like the Vax and 68000, where normally all arguments
+   are pushed, zero suffices as a definition.
+
+   The value of the expression can also be a `parallel' RTX.  This is
+   used when an argument is passed in multiple locations.  The mode
+   of the of the `parallel' should be the mode of the entire
+   argument.  The `parallel' holds any number of `expr_list' pairs;
+   each one describes where part of the argument is passed.  In each
+   `expr_list', the first operand can be either a `reg' RTX for the
+   hard register in which to pass this part of the argument, or zero
+   to pass the argument on the stack.  If this operand is a `reg',
+   then the mode indicates how large this part of the argument is.
+   The second operand of the `expr_list' is a `const_int' which gives
+   the offset in bytes into the entire argument where this part
+   starts.
+
+   The usual way to make the ANSI library `stdarg.h' work on a machine
+   where some arguments are usually passed in registers, is to cause
+   nameless arguments to be passed on the stack instead.  This is done
+   by making `FUNCTION_ARG' return 0 whenever NAMED is 0.
+
+   You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the
+   definition of this macro to determine if this argument is of a
+   type that must be passed in the stack.  If `REG_PARM_STACK_SPACE'
+   is not defined and `FUNCTION_ARG' returns non-zero for such an
+   argument, the compiler will abort.  If `REG_PARM_STACK_SPACE' is
+   defined, the argument will be computed in the stack and then
+   loaded into a register.  */
+
+typedef struct avr_args {
+  int nregs;                   /* # registers available for passing */
+  int regno;                   /* next available register number */
+} CUMULATIVE_ARGS;
+/* A C type for declaring a variable that is used as the first
+   argument of `FUNCTION_ARG' and other related values.  For some
+   target machines, the type `int' suffices and can hold the number
+   of bytes of argument so far.
+
+   There is no need to record in `CUMULATIVE_ARGS' anything about the
+   arguments that have been passed on the stack.  The compiler has
+   other variables to keep track of that.  For target machines on
+   which all arguments are passed on the stack, there is no need to
+   store anything in `CUMULATIVE_ARGS'; however, the data structure
+   must exist and should not be empty, so use `int'.  */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) init_cumulative_args (&(CUM), FNTYPE, LIBNAME, INDIRECT)
+
+/* A C statement (sans semicolon) for initializing the variable CUM
+   for the state at the beginning of the argument list.  The variable
+   has type `CUMULATIVE_ARGS'.  The value of FNTYPE is the tree node
+   for the data type of the function which will receive the args, or 0
+   if the args are to a compiler support library function.  The value
+   of INDIRECT is nonzero when processing an indirect call, for
+   example a call through a function pointer.  The value of INDIRECT
+   is zero for a call to an explicitly named function, a library
+   function call, or when `INIT_CUMULATIVE_ARGS' is used to find
+   arguments for the function being compiled.
+   
+   When processing a call to a compiler support library function,
+   LIBNAME identifies which one.  It is a `symbol_ref' rtx which
+   contains the name of the function, as a string.  LIBNAME is 0 when
+   an ordinary C function call is being processed.  Thus, each time
+   this macro is called, either LIBNAME or FNTYPE is nonzero, but
+   never both of them at once.   */
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)   \
+  (function_arg_advance (&CUM, MODE, TYPE, NAMED))
+
+/* A C statement (sans semicolon) to update the summarizer variable
+   CUM to advance past an argument in the argument list.  The values
+   MODE, TYPE and NAMED describe that argument.  Once this is done,
+   the variable CUM is suitable for analyzing the *following*
+   argument with `FUNCTION_ARG', etc.
+   
+   This macro need not do anything if the argument in question was
+   passed on the stack.  The compiler knows how to track the amount
+   of stack space used for arguments without any special help. */
+
+#define FUNCTION_ARG_REGNO_P(r) function_arg_regno_p(r)
+/* A C expression that is nonzero if REGNO is the number of a hard
+   register in which function arguments are sometimes passed.  This
+   does *not* include implicit arguments such as the static chain and
+   the structure-value address.  On many machines, no registers can be
+   used for this purpose since all function arguments are pushed on
+   the stack.  */
+
+extern int avr_reg_order[];
+
+#define RET_REGISTER avr_ret_register ()
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) avr_function_value (VALTYPE, FUNC)
+/* A C expression to create an RTX representing the place where a
+   function returns a value of data type VALTYPE.  VALTYPE is a tree
+   node representing a data type.  Write `TYPE_MODE (VALTYPE)' to get
+   the machine mode used to represent that type.  On many machines,
+   only the mode is relevant.  (Actually, on most machines, scalar
+   values are returned in the same place regardless of mode).
+
+   The value of the expression is usually a `reg' RTX for the hard
+   register where the return value is stored.  The value can also be a
+   `parallel' RTX, if the return value is in multiple places.  See
+   `FUNCTION_ARG' for an explanation of the `parallel' form.
+
+   If `PROMOTE_FUNCTION_RETURN' is defined, you must apply the same
+   promotion rules specified in `PROMOTE_MODE' if VALTYPE is a scalar
+   type.
+
+   If the precise function being called is known, FUNC is a tree node
+   (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer.  This
+   makes it possible to use a different value-returning convention
+   for specific functions when all their calls are known.
+
+   `FUNCTION_VALUE' is not used for return vales with aggregate data
+   types, because these are returned in another way.  See
+   `STRUCT_VALUE_REGNUM' and related macros, below.  */
+
+#define LIBCALL_VALUE(MODE)  avr_libcall_value (MODE)
+/* A C expression to create an RTX representing the place where a
+   library function returns a value of mode MODE.  If the precise
+   function being called is known, FUNC is a tree node
+   (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer.  This
+   makes it possible to use a different value-returning convention
+   for specific functions when all their calls are known.
+
+   Note that "library function" in this context means a compiler
+   support routine, used to perform arithmetic, whose name is known
+   specially by the compiler and was not mentioned in the C code being
+   compiled.
+
+   The definition of `LIBRARY_VALUE' need not be concerned aggregate
+   data types, because none of the library functions returns such
+   types.  */
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == RET_REGISTER)
+/* A C expression that is nonzero if REGNO is the number of a hard
+   register in which the values of called function may come back.
+
+   A register whose use for returning values is limited to serving as
+   the second of a pair (for a value of type `double', say) need not
+   be recognized by this macro.  So for most machines, this definition
+   suffices:
+
+   #define FUNCTION_VALUE_REGNO_P(N) ((N) == 0)
+
+   If the machine has register windows, so that the caller and the
+   called function use different registers for the return value, this
+   macro should recognize only the caller's register numbers.  */
+
+#define RETURN_IN_MEMORY(TYPE) ((TYPE_MODE (TYPE) == BLKmode)  \
+                               ? int_size_in_bytes (TYPE) > 8  \
+                               : 0)
+/* A C expression which can inhibit the returning of certain function
+   values in registers, based on the type of value.  A nonzero value
+   says to return the function value in memory, just as large
+   structures are always returned.  Here TYPE will be a C expression
+   of type `tree', representing the data type of the value.
+
+   Note that values of mode `BLKmode' must be explicitly handled by
+   this macro.  Also, the option `-fpcc-struct-return' takes effect
+   regardless of this macro.  On most systems, it is possible to
+   leave the macro undefined; this causes a default definition to be
+   used, whose value is the constant 1 for `BLKmode' values, and 0
+   otherwise.
+
+   Do not use this macro to indicate that structures and unions
+   should always be returned in memory.  You should instead use
+   `DEFAULT_PCC_STRUCT_RETURN' to indicate this.  */
+
+#define DEFAULT_PCC_STRUCT_RETURN 0
+/* Define this macro to be 1 if all structure and union return values
+   must be in memory.  Since this results in slower code, this should
+   be defined only if needed for compatibility with other compilers
+   or with an ABI.  If you define this macro to be 0, then the
+   conventions used for structure and union return values are decided
+   by the `RETURN_IN_MEMORY' macro.
+
+   If not defined, this defaults to the value 1.  */
+
+#define STRUCT_VALUE 0
+/* If the structure value address is not passed in a register, define
+   `STRUCT_VALUE' as an expression returning an RTX for the place
+   where the address is passed.  If it returns 0, the address is
+   passed as an "invisible" first argument.  */
+
+#define STRUCT_VALUE_INCOMING 0
+/* If the incoming location is not a register, then you should define
+   `STRUCT_VALUE_INCOMING' as an expression for an RTX for where the
+   called function should find the value.  If it should find the
+   value on the stack, define this to create a `mem' which refers to
+   the frame pointer.  A definition of 0 means that the address is
+   passed as an "invisible" first argument.  */
+
+#define FUNCTION_PROLOGUE(FILE, SIZE) function_prologue (FILE, SIZE)
+/* A C compound statement that outputs the assembler code for entry
+   to a function.  The prologue is responsible for setting up the
+   stack frame, initializing the frame pointer register, saving
+   registers that must be saved, and allocating SIZE additional bytes
+   of storage for the local variables.  SIZE is an integer.  FILE is
+   a stdio stream to which the assembler code should be output.
+
+   The label for the beginning of the function need not be output by
+   this macro.  That has already been done when the macro is run.
+
+   To determine which registers to save, the macro can refer to the
+   array `regs_ever_live': element R is nonzero if hard register R is
+   used anywhere within the function.  This implies the function
+   prologue should save register R, provided it is not one of the
+   call-used registers.  (`FUNCTION_EPILOGUE' must likewise use
+   `regs_ever_live'.)
+
+   On machines that have "register windows", the function entry code
+   does not save on the stack the registers that are in the windows,
+   even if they are supposed to be preserved by function calls;
+   instead it takes appropriate steps to "push" the register stack,
+   if any non-call-used registers are used in the function.
+
+   On machines where functions may or may not have frame-pointers, the
+   function entry code must vary accordingly; it must set up the frame
+   pointer if one is wanted, and not otherwise.  To determine whether
+   a frame pointer is in wanted, the macro can refer to the variable
+   `frame_pointer_needed'.  The variable's value will be 1 at run
+   time in a function that needs a frame pointer.  *Note
+   Elimination::.
+
+   The function entry code is responsible for allocating any stack
+   space required for the function.  This stack space consists of the
+   regions listed below.  In most cases, these regions are allocated
+   in the order listed, with the last listed region closest to the
+   top of the stack (the lowest address if `STACK_GROWS_DOWNWARD' is
+   defined, and the highest address if it is not defined).  You can
+   use a different order for a machine if doing so is more convenient
+   or required for compatibility reasons.  Except in cases where
+   required by standard or by a debugger, there is no reason why the
+   stack layout used by GCC need agree with that used by other
+   compilers for a machine.
+
+   * A region of `current_function_pretend_args_size' bytes of
+   uninitialized space just underneath the first argument
+   arriving on the stack.  (This may not be at the very start of
+   the allocated stack region if the calling sequence has pushed
+   anything else since pushing the stack arguments.  But
+   usually, on such machines, nothing else has been pushed yet,
+   because the function prologue itself does all the pushing.)
+   This region is used on machines where an argument may be
+   passed partly in registers and partly in memory, and, in some
+   cases to support the features in `varargs.h' and `stdargs.h'.
+
+   * An area of memory used to save certain registers used by the
+   function.  The size of this area, which may also include
+   space for such things as the return address and pointers to
+   previous stack frames, is machine-specific and usually
+   depends on which registers have been used in the function.
+   Machines with register windows often do not require a save
+   area.
+
+   * A region of at least SIZE bytes, possibly rounded up to an
+   allocation boundary, to contain the local variables of the
+   function.  On some machines, this region and the save area
+   may occur in the opposite order, with the save area closer to
+   the top of the stack.
+
+   * Optionally, when `ACCUMULATE_OUTGOING_ARGS' is defined, a
+   region of `current_function_outgoing_args_size' bytes to be
+   used for outgoing argument lists of the function.  *Note
+   Stack Arguments::.
+
+   Normally, it is necessary for the macros `FUNCTION_PROLOGUE' and
+   `FUNCTION_EPILOGE' to treat leaf functions specially.  The C
+   variable `leaf_function' is nonzero for such a function.  */
+
+#define EPILOGUE_USES(REGNO) 0
+/* Define this macro as a C expression that is nonzero for registers
+   are used by the epilogue or the `return' pattern.  The stack and
+   frame pointer registers are already be assumed to be used as
+   needed.  */
+
+#define FUNCTION_EPILOGUE(FILE, SIZE) function_epilogue (FILE, SIZE)
+/* A C compound statement that outputs the assembler code for exit
+   from a function.  The epilogue is responsible for restoring the
+   saved registers and stack pointer to their values when the
+   function was called, and returning control to the caller.  This
+   macro takes the same arguments as the macro `FUNCTION_PROLOGUE',
+   and the registers to restore are determined from `regs_ever_live'
+   and `CALL_USED_REGISTERS' in the same way.
+
+   On some machines, there is a single instruction that does all the
+   work of returning from the function.  On these machines, give that
+   instruction the name `return' and do not define the macro
+   `FUNCTION_EPILOGUE' at all.
+
+   Do not define a pattern named `return' if you want the
+   `FUNCTION_EPILOGUE' to be used.  If you want the target switches
+   to control whether return instructions or epilogues are used,
+   define a `return' pattern with a validity condition that tests the
+   target switches appropriately.  If the `return' pattern's validity
+   condition is false, epilogues will be used.
+
+   On machines where functions may or may not have frame-pointers, the
+   function exit code must vary accordingly.  Sometimes the code for
+   these two cases is completely different.  To determine whether a
+   frame pointer is wanted, the macro can refer to the variable
+   `frame_pointer_needed'.  The variable's value will be 1 when
+   compiling a function that needs a frame pointer.
+
+   Normally, `FUNCTION_PROLOGUE' and `FUNCTION_EPILOGUE' must treat
+   leaf functions specially.  The C variable `leaf_function' is
+   nonzero for such a function.  *Note Leaf Functions::.
+
+   On some machines, some functions pop their arguments on exit while
+   others leave that for the caller to do.  For example, the 68020
+   when given `-mrtd' pops arguments in functions that take a fixed
+   number of arguments.
+
+   Your definition of the macro `RETURN_POPS_ARGS' decides which
+   functions pop their own arguments.  `FUNCTION_EPILOGUE' needs to
+   know what was decided.  The variable that is called
+   `current_function_pops_args' is the number of bytes of its
+   arguments that a function should pop.  *Note Scalar Return::.  */
+
+#define STRICT_ARGUMENT_NAMING 1
+/* Define this macro if the location where a function argument is
+   passed depends on whether or not it is a named argument.
+
+   This macro controls how the NAMED argument to `FUNCTION_ARG' is
+   set for varargs and stdarg functions.  With this macro defined,
+   the NAMED argument is always true for named arguments, and false
+   for unnamed arguments.  If this is not defined, but
+   `SETUP_INCOMING_VARARGS' is defined, then all arguments are
+   treated as named.  Otherwise, all named arguments except the last
+   are treated as named.  */
+
+
+#define HAVE_POST_INCREMENT 1
+/* Define this macro if the machine supports post-increment
+   addressing.  */
+
+#define HAVE_PRE_DECREMENT 1
+/* #define HAVE_PRE_INCREMENT
+   #define HAVE_POST_DECREMENT  */
+/* Similar for other kinds of addressing.  */
+
+#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
+/* A C expression that is 1 if the RTX X is a constant which is a
+   valid address.  On most machines, this can be defined as
+   `CONSTANT_P (X)', but a few machines are more restrictive in which
+   constant addresses are supported.
+
+   `CONSTANT_P' accepts integer-values expressions whose values are
+   not explicitly known, such as `symbol_ref', `label_ref', and
+   `high' expressions and `const' arithmetic expressions, in addition
+   to `const_int' and `const_double' expressions.  */
+
+#define MAX_REGS_PER_ADDRESS 1
+/* A number, the maximum number of registers that can appear in a
+   valid memory address.  Note that it is up to you to specify a
+   value equal to the maximum number that `GO_IF_LEGITIMATE_ADDRESS'
+   would ever accept.  */
+
+#ifdef REG_OK_STRICT
+#  define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR)        \
+{                                                      \
+  if (legitimate_address_p (mode, operand, 1))         \
+    goto ADDR;                                         \
+}
+#  else
+#  define GO_IF_LEGITIMATE_ADDRESS(mode, operand, ADDR)        \
+{                                                      \
+  if (legitimate_address_p (mode, operand, 0))         \
+    goto ADDR;                                         \
+}
+#endif
+/* A C compound statement with a conditional `goto LABEL;' executed
+   if X (an RTX) is a legitimate memory address on the target machine
+   for a memory operand of mode MODE.
+
+   It usually pays to define several simpler macros to serve as
+   subroutines for this one.  Otherwise it may be too complicated to
+   understand.
+
+   This macro must exist in two variants: a strict variant and a
+   non-strict one.  The strict variant is used in the reload pass.  It
+   must be defined so that any pseudo-register that has not been
+   allocated a hard register is considered a memory reference.  In
+   contexts where some kind of register is required, a pseudo-register
+   with no hard register must be rejected.
+
+   The non-strict variant is used in other passes.  It must be
+   defined to accept all pseudo-registers in every context where some
+   kind of register is required.
+
+   Compiler source files that want to use the strict variant of this
+   macro define the macro `REG_OK_STRICT'.  You should use an `#ifdef
+   REG_OK_STRICT' conditional to define the strict variant in that
+   case and the non-strict variant otherwise.
+
+   Subroutines to check for acceptable registers for various purposes
+   (one for base registers, one for index registers, and so on) are
+   typically among the subroutines used to define
+   `GO_IF_LEGITIMATE_ADDRESS'.  Then only these subroutine macros
+   need have two variants; the higher levels of macros may be the
+   same whether strict or not.
+
+   Normally, constant addresses which are the sum of a `symbol_ref'
+   and an integer are stored inside a `const' RTX to mark them as
+   constant.  Therefore, there is no need to recognize such sums
+   specifically as legitimate addresses.  Normally you would simply
+   recognize any `const' as legitimate.
+
+   Usually `PRINT_OPERAND_ADDRESS' is not prepared to handle constant
+   sums that are not marked with  `const'.  It assumes that a naked
+   `plus' indicates indexing.  If so, then you *must* reject such
+   naked constant sums as illegitimate addresses, so that none of
+   them will be given to `PRINT_OPERAND_ADDRESS'.
+
+   On some machines, whether a symbolic address is legitimate depends
+   on the section that the address refers to.  On these machines,
+   define the macro `ENCODE_SECTION_INFO' to store the information
+   into the `symbol_ref', and then check for it here.  When you see a
+   `const', you will have to look inside it to find the `symbol_ref'
+   in order to determine the section.  *Note Assembler Format::.
+
+   The best way to modify the name string is by adding text to the
+   beginning, with suitable punctuation to prevent any ambiguity.
+   Allocate the new name in `saveable_obstack'.  You will have to
+   modify `ASM_OUTPUT_LABELREF' to remove and decode the added text
+   and output the name accordingly, and define `STRIP_NAME_ENCODING'
+   to access the original name string.
+
+   You can check the information stored here into the `symbol_ref' in
+   the definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and
+   `PRINT_OPERAND_ADDRESS'. */
+
+/* `REG_OK_FOR_BASE_P (X)'
+   A C expression that is nonzero if X (assumed to be a `reg' RTX) is
+   valid for use as a base register.  For hard registers, it should
+   always accept those which the hardware permits and reject the
+   others.  Whether the macro accepts or rejects pseudo registers
+   must be controlled by `REG_OK_STRICT' as described above.  This
+   usually requires two variant definitions, of which `REG_OK_STRICT'
+   controls the one actually used.  */
+
+#define REG_OK_FOR_BASE_NOSTRICT_P(X) \
+  (REGNO (X) >= FIRST_PSEUDO_REGISTER || REG_OK_FOR_BASE_STRICT_P(X))
+
+#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+
+#ifdef REG_OK_STRICT
+#  define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X)
+#else
+#  define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NOSTRICT_P (X)
+#endif
+
+/* A C expression that is just like `REG_OK_FOR_BASE_P', except that
+   that expression may examine the mode of the memory reference in
+   MODE.  You should define this macro if the mode of the memory
+   reference affects whether a register may be used as a base
+   register.  If you define this macro, the compiler will use it
+   instead of `REG_OK_FOR_BASE_P'.  */
+#define REG_OK_FOR_INDEX_P(X) 0
+/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is
+   valid for use as an index register.
+
+   The difference between an index register and a base register is
+   that the index register may be scaled.  If an address involves the
+   sum of two registers, neither one of them scaled, then either one
+   may be labeled the "base" and the other the "index"; but whichever
+   labeling is used must fit the machine's constraints of which
+   registers may serve in each capacity.  The compiler will try both
+   labelings, looking for one that is valid, and will reload one or
+   both registers only if neither labeling works.  */
+
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)                         \
+{                                                                      \
+  (X) = legitimize_address (X, OLDX, MODE);                            \
+  if (memory_address_p (MODE, X))                                      \
+    goto WIN;                                                          \
+}
+/* A C compound statement that attempts to replace X with a valid
+   memory address for an operand of mode MODE.  WIN will be a C
+   statement label elsewhere in the code; the macro definition may use
+
+   GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
+
+   to avoid further processing if the address has become legitimate.
+
+   X will always be the result of a call to `break_out_memory_refs',
+   and OLDX will be the operand that was given to that function to
+   produce X.
+
+   The code generated by this macro should not alter the substructure
+   of X.  If it transforms X into a more legitimate form, it should
+   assign X (which will always be a C variable) a new value.
+
+   It is not necessary for this macro to come up with a legitimate
+   address.  The compiler has standard ways of doing so in all cases.
+   In fact, it is safe for this macro to do nothing.  But often a
+   machine-dependent strategy can generate better code.  */
+
+#define XEXP_(X,Y) (X)
+#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND_LEVELS, WIN)    \
+do {                                                                       \
+  if (1&&(GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC))            \
+    {                                                                      \
+      push_reload (XEXP (X,0), XEXP (X,0), &XEXP (X,0), &XEXP (X,0),       \
+                  POINTER_REGS, GET_MODE (X),GET_MODE (X) , 0, 0,          \
+                  OPNUM, RELOAD_OTHER);                                    \
+      goto WIN;                                                                    \
+    }                                                                      \
+  if (GET_CODE (X) == PLUS                                                 \
+      && REG_P (XEXP (X, 0))                                               \
+      && GET_CODE (XEXP (X, 1)) == CONST_INT                               \
+      && INTVAL (XEXP (X, 1)) >= 1)                                        \
+    {                                                                      \
+      int fit = INTVAL (XEXP (X, 1)) <= (64 - GET_MODE_SIZE (MODE));       \
+      if (fit)                                                             \
+       {                                                                   \
+          if (reg_equiv_address[REGNO (XEXP (X, 0))] != 0)                 \
+           {                                                               \
+             int regno = REGNO (XEXP (X, 0));                              \
+             rtx mem = make_memloc (X, regno);                             \
+             push_reload (XEXP (mem,0), NULL_PTR, &XEXP (mem,0), NULL_PTR, \
+                          POINTER_REGS, Pmode, VOIDmode, 0, 0,             \
+                          1, ADDR_TYPE (TYPE));                            \
+             push_reload (mem, NULL_RTX, &XEXP (X, 0), NULL_PTR,           \
+                          BASE_POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0, \
+                          OPNUM, TYPE);                                    \
+             goto WIN;                                                     \
+           }                                                               \
+         push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR,       \
+                      BASE_POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0,     \
+                      OPNUM, TYPE);                                        \
+          goto WIN;                                                        \
+       }                                                                   \
+      else if (! (frame_pointer_needed && XEXP (X,0) == frame_pointer_rtx)) \
+       {                                                                   \
+         push_reload (X, NULL_RTX, &X, NULL_PTR,                           \
+                      POINTER_REGS, GET_MODE (X), VOIDmode, 0, 0,          \
+                      OPNUM, TYPE);                                        \
+          goto WIN;                                                        \
+       }                                                                   \
+    }                                                                      \
+} while(0)
+/* A C compound statement that attempts to replace X, which is an
+   address that needs reloading, with a valid memory address for an
+   operand of mode MODE.  WIN will be a C statement label elsewhere
+   in the code.  It is not necessary to define this macro, but it
+   might be useful for performance reasons.
+
+   For example, on the i386, it is sometimes possible to use a single
+   reload register instead of two by reloading a sum of two pseudo
+   registers into a register.  On the other hand, for number of RISC
+   processors offsets are limited so that often an intermediate
+   address needs to be generated in order to address a stack slot.
+   By defining LEGITIMIZE_RELOAD_ADDRESS appropriately, the
+   intermediate addresses generated for adjacent some stack slots can
+   be made identical, and thus be shared.
+
+   *Note*: This macro should be used with caution.  It is necessary
+   to know something of how reload works in order to effectively use
+   this, and it is quite easy to produce macros that build in too
+   much knowledge of reload internals.
+
+   *Note*: This macro must be able to reload an address created by a
+   previous invocation of this macro.  If it fails to handle such
+   addresses then the compiler may generate incorrect code or abort.
+
+   The macro definition should use `push_reload' to indicate parts
+   that need reloading; OPNUM, TYPE and IND_LEVELS are usually
+   suitable to be passed unaltered to `push_reload'.
+
+   The code generated by this macro must not alter the substructure of
+   X.  If it transforms X into a more legitimate form, it should
+   assign X (which will always be a C variable) a new value.  This
+   also applies to parts that you change indirectly by calling
+   `push_reload'.
+
+   The macro definition may use `strict_memory_address_p' to test if
+   the address has become legitimate.
+
+   If you want to change only a part of X, one standard way of doing
+   this is to use `copy_rtx'.  Note, however, that is unshares only a
+   single level of rtl.  Thus, if the part to be changed is not at the
+   top level, you'll need to replace first the top leve It is not
+   necessary for this macro to come up with a legitimate address;
+   but often a machine-dependent strategy can generate better code.  */
+       
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)                       \
+      if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC)   \
+        goto LABEL
+/* A C statement or compound statement with a conditional `goto
+   LABEL;' executed if memory address X (an RTX) can have different
+   meanings depending on the machine mode of the memory reference it
+   is used for or if the address is valid for some modes but not
+   others.
+
+   Autoincrement and autodecrement addresses typically have
+   mode-dependent effects because the amount of the increment or
+   decrement is the size of the operand being addressed.  Some
+   machines have other mode-dependent addresses.  Many RISC machines
+   have no mode-dependent addresses.
+
+   You may assume that ADDR is a valid address for the machine.  */
+
+#define LEGITIMATE_CONSTANT_P(X) 1
+/* A C expression that is nonzero if X is a legitimate constant for
+   an immediate operand on the target machine.  You can assume that X
+   satisfies `CONSTANT_P', so you need not check this.  In fact, `1'
+   is a suitable definition for this macro on machines where anything
+   `CONSTANT_P' is valid.  */
+
+#define CONST_COSTS(x,CODE,OUTER_CODE)         \
+    case CONST_INT:                            \
+      if (OUTER_CODE == PLUS                   \
+         || OUTER_CODE == IOR                  \
+         || OUTER_CODE == AND                  \
+         || OUTER_CODE == MINUS                \
+         || OUTER_CODE == SET                  \
+         || INTVAL (x) == 0)                   \
+        return 2;                              \
+      if (OUTER_CODE == COMPARE                        \
+         && INTVAL (x) >= 0                    \
+         && INTVAL (x) <= 255)                 \
+        return 2;                              \
+    case CONST:                                        \
+    case LABEL_REF:                            \
+    case SYMBOL_REF:                           \
+      return 4;                                        \
+    case CONST_DOUBLE:                         \
+      return 4;
+
+/* A part of a C `switch' statement that describes the relative costs
+   of constant RTL expressions.  It must contain `case' labels for
+   expression codes `const_int', `const', `symbol_ref', `label_ref'
+   and `const_double'.  Each case must ultimately reach a `return'
+   statement to return the relative cost of the use of that kind of
+   constant value in an expression.  The cost may depend on the
+   precise value of the constant, which is available for examination
+   in X, and the rtx code of the expression in which it is contained,
+   found in OUTER_CODE.
+
+   CODE is the expression code--redundant, since it can be obtained
+   with `GET_CODE (X)'.  */
+
+#define DEFAULT_RTX_COSTS(x, code, outer_code)         \
+{                                                      \
+  int cst = default_rtx_costs (x, code, outer_code);   \
+  if (cst>0)                                           \
+    return cst;                                        \
+  else if (cst<0)                                      \
+    total += -cst;                                     \
+  break;                                               \
+}
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
+   This can be used, for example, to indicate how costly a multiply
+   instruction is.  In writing this macro, you can use the construct
+   `COSTS_N_INSNS (N)' to specify a cost equal to N fast
+   instructions.  OUTER_CODE is the code of the expression in which X
+   is contained.
+
+   This macro is optional; do not define it if the default cost
+   assumptions are adequate for the target machine.  */
+
+#define ADDRESS_COST(ADDRESS) address_cost (ADDRESS)
+
+/* An expression giving the cost of an addressing mode that contains
+   ADDRESS.  If not defined, the cost is computed from the ADDRESS
+   expression and the `CONST_COSTS' values.
+
+   For most CISC machines, the default cost is a good approximation
+   of the true cost of the addressing mode.  However, on RISC
+   machines, all instructions normally have the same length and
+   execution time.  Hence all addresses will have equal costs.
+
+   In cases where more than one form of an address is known, the form
+   with the lowest cost will be used.  If multiple forms have the
+   same, lowest, cost, the one that is the most complex will be used.
+
+   For example, suppose an address that is equal to the sum of a
+   register and a constant is used twice in the same basic block.
+   When this macro is not defined, the address will be computed in a
+   register and memory references will be indirect through that
+   register.  On machines where the cost of the addressing mode
+   containing the sum is no higher than that of a simple indirect
+   reference, this will produce an additional instruction and
+   possibly require an additional register.  Proper specification of
+   this macro eliminates this overhead for such machines.
+
+   Similar use of this macro is made in strength reduction of loops.
+
+   ADDRESS need not be valid as an address.  In such a case, the cost
+   is not relevant and can be any value; invalid addresses need not be
+   assigned a different cost.
+
+   On machines where an address involving more than one register is as
+   cheap as an address computation involving only one register,
+   defining `ADDRESS_COST' to reflect this can cause two registers to
+   be live over a region of code where only one would have been if
+   `ADDRESS_COST' were not defined in that manner.  This effect should
+   be considered in the definition of this macro.  Equivalent costs
+   should probably only be given to addresses with different numbers
+   of registers on machines with lots of registers.
+
+   This macro will normally either not be defined or be defined as a
+   constant.  */
+
+#define REGISTER_MOVE_COST(FROM, TO) ((FROM) == STACK_REG ? 6 : \
+                                     (TO) == STACK_REG ? 12    \
+                                     : 2)
+/* A C expression for the cost of moving data from a register in class
+   FROM to one in class TO.  The classes are expressed using the
+   enumeration values such as `GENERAL_REGS'.  A value of 2 is the
+   default; other values are interpreted relative to that.
+
+   It is not required that the cost always equal 2 when FROM is the
+   same as TO; on some machines it is expensive to move between
+   registers if they are not general registers.
+
+   If reload sees an insn consisting of a single `set' between two
+   hard registers, and if `REGISTER_MOVE_COST' applied to their
+   classes returns a value of 2, reload does not check to ensure that
+   the constraints of the insn are met.  Setting a cost of other than
+   2 will allow reload to verify that the constraints are met.  You
+   should do this if the `movM' pattern's constraints do not allow
+   such copying.  */
+
+#define MEMORY_MOVE_COST(MODE,CLASS,IN) ((MODE)==QImode ? 2 :  \
+                                        (MODE)==HImode ? 4 :   \
+                                        (MODE)==SImode ? 8 :   \
+                                        (MODE)==SFmode ? 8 : 16)
+/* A C expression for the cost of moving data of mode M between a
+   register and memory.  A value of 4 is the default; this cost is
+   relative to those in `REGISTER_MOVE_COST'.
+
+   If moving between registers and memory is more expensive than
+   between two registers, you should define this macro to express the
+   relative cost.  */
+
+#define SLOW_BYTE_ACCESS 0
+/* Define this macro as a C expression which is nonzero if accessing
+   less than a word of memory (i.e. a `char' or a `short') is no
+   faster than accessing a word of memory, i.e., if such access
+   require more than one instruction or if there is no difference in
+   cost between byte and (aligned) word loads.
+
+   When this macro is not defined, the compiler will access a field by
+   finding the smallest containing object; when it is defined, a
+   fullword load will be used if alignment permits.  Unless bytes
+   accesses are faster than word accesses, using word accesses is
+   preferable since it may eliminate subsequent memory access if
+   subsequent accesses occur to other fields in the same word of the
+   structure, but to different bytes.
+
+   `SLOW_ZERO_EXTEND'
+   Define this macro if zero-extension (of a `char' or `short' to an
+   `int') can be done faster if the destination is a register that is
+   known to be zero.
+
+   If you define this macro, you must have instruction patterns that
+   recognize RTL structures like this:
+
+   (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
+
+   and likewise for `HImode'.
+
+   `SLOW_UNALIGNED_ACCESS'
+   Define this macro to be the value 1 if unaligned accesses have a
+   cost many times greater than aligned accesses, for example if they
+   are emulated in a trap handler.
+
+   When this macro is non-zero, the compiler will act as if
+   `STRICT_ALIGNMENT' were non-zero when generating code for block
+   moves.  This can cause significantly more instructions to be
+   produced.  Therefore, do not set this macro non-zero if unaligned
+   accesses only add a cycle or two to the time for a memory access.
+
+   If the value of this macro is always zero, it need not be defined.
+
+   `DONT_REDUCE_ADDR'
+   Define this macro to inhibit strength reduction of memory
+   addresses.  (On some machines, such strength reduction seems to do
+   harm rather than good.)
+
+   `MOVE_RATIO'
+   The number of scalar move insns which should be generated instead
+   of a string move insn or a library call.  Increasing the value
+   will always make code faster, but eventually incurs high cost in
+   increased code size.
+
+   If you don't define this, a reasonable default is used.  */
+
+#define NO_FUNCTION_CSE
+/* Define this macro if it is as good or better to call a constant
+   function address than to call an address kept in a register.  */
+
+#define NO_RECURSIVE_FUNCTION_CSE
+/* Define this macro if it is as good or better for a function to call
+   itself with an explicit address than to call an address kept in a
+   register.
+
+   `ADJUST_COST (INSN, LINK, DEP_INSN, COST)'
+   A C statement (sans semicolon) to update the integer variable COST
+   based on the relationship between INSN that is dependent on
+   DEP_INSN through the dependence LINK.  The default is to make no
+   adjustment to COST.  This can be used for example to specify to
+   the scheduler that an output- or anti-dependence does not incur
+   the same cost as a data-dependence.
+
+   `ADJUST_PRIORITY (INSN)'
+   A C statement (sans semicolon) to update the integer scheduling
+   priority `INSN_PRIORITY(INSN)'.  Reduce the priority to execute
+   the INSN earlier, increase the priority to execute INSN later.
+   Do not define this macro if you do not need to adjust the
+   scheduling priorities of insns.  */
+
+
+#define TEXT_SECTION_ASM_OP ".text"
+/* A C expression whose value is a string containing the assembler
+   operation that should precede instructions and read-only data.
+   Normally `".text"' is right.  */
+
+#define DATA_SECTION_ASM_OP ".data"
+/* A C expression whose value is a string containing the assembler
+   operation to identify the following data as writable initialized
+   data.  Normally `".data"' is right.  */
+
+#define EXTRA_SECTIONS in_progmem
+/* A list of names for sections other than the standard two, which are
+   `in_text' and `in_data'.  You need not define this macro on a
+   system with no other sections (that GCC needs to use).  */
+
+#define EXTRA_SECTION_FUNCTIONS                                                      \
+                                                                             \
+void                                                                         \
+progmem_section (void)                                                       \
+{                                                                            \
+  if (in_section != in_progmem)                                                      \
+    {                                                                        \
+      fprintf (asm_out_file, ".section .progmem.gcc_sw_table\n");            \
+      in_section = in_progmem;                                               \
+    }                                                                        \
+}
+/* `EXTRA_SECTION_FUNCTIONS'
+   One or more functions to be defined in `varasm.c'.  These
+   functions should do jobs analogous to those of `text_section' and
+   `data_section', for your additional sections.  Do not define this
+   macro if you do not define `EXTRA_SECTIONS'.  */
+
+#define READONLY_DATA_SECTION data_section
+/* On most machines, read-only variables, constants, and jump tables
+   are placed in the text section.  If this is not the case on your
+   machine, this macro should be defined to be the name of a function
+   (either `data_section' or a function defined in `EXTRA_SECTIONS')
+   that switches to the section to be used for read-only items.
+
+   If these items should be placed in the text section, this macro
+   should not be defined.  */
+
+/* `SELECT_SECTION (EXP, RELOC)'
+   A C statement or statements to switch to the appropriate section
+   for output of EXP.  You can assume that EXP is either a `VAR_DECL'
+   node or a constant of some sort.  RELOC indicates whether the
+   initial value of EXP requires link-time relocations.  Select the
+   section by calling `text_section' or one of the alternatives for
+   other sections.
+
+   Do not define this macro if you put all read-only variables and
+   constants in the read-only data section (usually the text section).  */
+
+/* `SELECT_RTX_SECTION (MODE, RTX)'
+   A C statement or statements to switch to the appropriate section
+   for output of RTX in mode MODE.  You can assume that RTX is some
+   kind of constant in RTL.  The argument MODE is redundant except in
+   the case of a `const_int' rtx.  Select the section by calling
+   `text_section' or one of the alternatives for other sections.
+
+   Do not define this macro if you put all constants in the read-only
+   data section.  */
+
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+/* Define this macro if jump tables (for `tablejump' insns) should be
+   output in the text section, along with the assembler instructions.
+   Otherwise, the readonly data section is used.
+
+   This macro is irrelevant if there is no separate readonly data
+   section.  */
+
+#define ENCODE_SECTION_INFO(DECL)  encode_section_info(DECL)
+/* Define this macro if references to a symbol must be treated
+   differently depending on something about the variable or function
+   named by the symbol (such as what section it is in).
+
+   The macro definition, if any, is executed immediately after the
+   rtl for DECL has been created and stored in `DECL_RTL (DECL)'.
+   The value of the rtl will be a `mem' whose address is a
+   `symbol_ref'.
+
+   The usual thing for this macro to do is to record a flag in the
+   `symbol_ref' (such as `SYMBOL_REF_FLAG') or to store a modified
+   name string in the `symbol_ref' (if one bit is not enough
+   information).  */
+
+#define STRIP_NAME_ENCODING(VAR,SYMBOL_NAME) \
+  (VAR) = (SYMBOL_NAME) + ((SYMBOL_NAME)[0] == '*' || (SYMBOL_NAME)[0] == '@');
+/* `STRIP_NAME_ENCODING (VAR, SYM_NAME)'
+   Decode SYM_NAME and store the real name part in VAR, sans the
+   characters that encode section info.  Define this macro if
+   `ENCODE_SECTION_INFO' alters the symbol's name string.  */
+/* `UNIQUE_SECTION_P (DECL)'
+   A C expression which evaluates to true if DECL should be placed
+   into a unique section for some target-specific reason.  If you do
+   not define this macro, the default is `0'.  Note that the flag
+   `-ffunction-sections' will also cause functions to be placed into
+   unique sections.  */
+
+#define UNIQUE_SECTION(DECL, RELOC) unique_section (DECL, RELOC)
+/* `UNIQUE_SECTION (DECL, RELOC)'
+   A C statement to build up a unique section name, expressed as a
+   STRING_CST node, and assign it to `DECL_SECTION_NAME (DECL)'.
+   RELOC indicates whether the initial value of EXP requires
+   link-time relocations.  If you do not define this macro, GNU CC
+   will use the symbol name prefixed by `.' as the section name.  */
+
+
+#define ASM_FILE_START(STREAM) asm_file_start (STREAM)
+/* A C expression which outputs to the stdio stream STREAM some
+   appropriate text to go at the start of an assembler file.
+
+   Normally this macro is defined to output a line containing
+   `#NO_APP', which is a comment that has no effect on most
+   assemblers but tells the GNU assembler that it can save time by not
+   checking for certain assembler constructs.
+
+   On systems that use SDB, it is necessary to output certain
+   commands; see `attasm.h'.  */
+
+#define ASM_FILE_END(STREAM) asm_file_end (STREAM)
+/* A C expression which outputs to the stdio stream STREAM some
+   appropriate text to go at the end of an assembler file.
+
+   If this macro is not defined, the default is to output nothing
+   special at the end of the file.  Most systems don't require any
+   definition.
+
+   On systems that use SDB, it is necessary to output certain
+   commands; see `attasm.h'.  */
+
+#define ASM_COMMENT_START " ; "
+/* A C string constant describing how to begin a comment in the target
+   assembler language.  The compiler assumes that the comment will
+   end at the end of the line.  */
+
+#define ASM_APP_ON "/* #APP */\n"
+/* A C string constant for text to be output before each `asm'
+   statement or group of consecutive ones.  Normally this is
+   `"#APP"', which is a comment that has no effect on most assemblers
+   but tells the GNU assembler that it must check the lines that
+   follow for all valid assembler constructs.  */
+
+#define ASM_APP_OFF "/* #NOAPP */\n"
+/* A C string constant for text to be output after each `asm'
+   statement or group of consecutive ones.  Normally this is
+   `"#NO_APP"', which tells the GNU assembler to resume making the
+   time-saving assumptions that are valid for ordinary compiler
+   output.  */
+
+#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) fprintf (STREAM,"/* line: %d */\n",LINE)
+/* A C statement to output DBX or SDB debugging information before
+   code for line number LINE of the current source file to the stdio
+   stream STREAM.
+
+   This macro need not be defined if the standard form of debugging
+   information for the debugger in use is appropriate.  */
+
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+  asm_output_section_name(FILE, DECL, NAME, RELOC)
+
+/* `ASM_OUTPUT_SECTION_NAME (STREAM, DECL, NAME, RELOC)'
+   A C statement to output something to the assembler file to switch
+   to section NAME for object DECL which is either a `FUNCTION_DECL',
+   a `VAR_DECL' or `NULL_TREE'.  RELOC indicates whether the initial
+   value of EXP requires link-time relocations.  Some target formats
+   do not support arbitrary sections.  Do not define this macro in
+   such cases.
+
+   At present this macro is only used to support section attributes.
+   When this macro is undefined, section attributes are disabled.  */
+
+#define OBJC_PROLOGUE {}
+/* A C statement to output any assembler statements which are
+   required to precede any Objective C object definitions or message
+   sending.  The statement is executed only when compiling an
+   Objective C program.  */
+
+
+
+#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) fprintf (STREAM, "no double float %.20e\n", VALUE)
+#define ASM_OUTPUT_FLOAT(STREAM, VALUE) asm_output_float (STREAM, VALUE)
+/* `ASM_OUTPUT_LONG_DOUBLE (STREAM, VALUE)'
+   `ASM_OUTPUT_THREE_QUARTER_FLOAT (STREAM, VALUE)'
+   `ASM_OUTPUT_SHORT_FLOAT (STREAM, VALUE)'
+   `ASM_OUTPUT_BYTE_FLOAT (STREAM, VALUE)'
+   A C statement to output to the stdio stream STREAM an assembler
+   instruction to assemble a floating-point constant of `TFmode',
+   `DFmode', `SFmode', `TQFmode', `HFmode', or `QFmode',
+   respectively, whose value is VALUE.  VALUE will be a C expression
+   of type `REAL_VALUE_TYPE'.  Macros such as
+   `REAL_VALUE_TO_TARGET_DOUBLE' are useful for writing these
+   definitions.  */
+
+
+#define ASM_OUTPUT_INT(FILE, VALUE)                    \
+ ( fprintf (FILE, "\t.long "),                         \
+   output_addr_const (FILE, (VALUE)),                  \
+   fputs ("\n", FILE))
+
+ /* Likewise for `short' and `char' constants.   */
+
+#define ASM_OUTPUT_SHORT(FILE,VALUE) asm_output_short(FILE,VALUE)
+#define ASM_OUTPUT_CHAR(FILE,VALUE) asm_output_char(FILE,VALUE)
+
+/* `ASM_OUTPUT_QUADRUPLE_INT (STREAM, EXP)'
+   A C statement to output to the stdio stream STREAM an assembler
+   instruction to assemble an integer of 16, 8, 4, 2 or 1 bytes,
+   respectively, whose value is VALUE.  The argument EXP will be an
+   RTL expression which represents a constant value.  Use
+   `output_addr_const (STREAM, EXP)' to output this value as an
+   assembler expression.
+
+   For sizes larger than `UNITS_PER_WORD', if the action of a macro
+   would be identical to repeatedly calling the macro corresponding to
+   a size of `UNITS_PER_WORD', once for each word, you need not define
+   the macro.  */
+
+
+#define ASM_OUTPUT_BYTE(FILE,VALUE) asm_output_byte (FILE,VALUE)
+/* A C statement to output to the stdio stream STREAM an assembler
+   instruction to assemble a single byte containing the number VALUE.  */
+
+#define ASM_BYTE_OP ".byte "
+/* A C string constant giving the pseudo-op to use for a sequence of
+   single-byte constants.  If this macro is not defined, the default
+   is `"byte"'.  */
+
+#define ASM_OUTPUT_ASCII(FILE, P, SIZE)         gas_output_ascii (FILE,P,SIZE)
+/* `ASM_OUTPUT_ASCII (STREAM, PTR, LEN)'
+   output_ascii (FILE, P, SIZE)
+   A C statement to output to the stdio stream STREAM an assembler
+   instruction to assemble a string constant containing the LEN bytes
+   at PTR.  PTR will be a C expression of type `char *' and LEN a C
+   expression of type `int'.
+
+   If the assembler has a `.ascii' pseudo-op as found in the Berkeley
+   Unix assembler, do not define the macro `ASM_OUTPUT_ASCII'.  */
+
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == '\n'                   \
+                                         || ((C) == '$'))
+/* Define this macro as a C expression which is nonzero if C is used
+   as a logical line separator by the assembler.
+
+   If you do not define this macro, the default is that only the
+   character `;' is treated as a logical line separator.  */
+
+#define ASM_OPEN_PAREN "("
+#define ASM_CLOSE_PAREN ")"
+/* These macros are defined as C string constant, describing the
+   syntax in the assembler for grouping arithmetic expressions.  The
+   following definitions are correct for most assemblers:
+
+   #define ASM_OPEN_PAREN "("
+   #define ASM_CLOSE_PAREN ")"
+
+   These macros are provided by `real.h' for writing the definitions of
+   `ASM_OUTPUT_DOUBLE' and the like:  */
+
+#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED)                    \
+do {                                                                      \
+     fputs ("\t.comm ", (STREAM));                                        \
+     assemble_name ((STREAM), (NAME));                                    \
+     fprintf ((STREAM), ",%d\n", (SIZE));                                 \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM the assembler definition of a common-label named NAME whose
+   size is SIZE bytes.  The variable ROUNDED is the size rounded up
+   to whatever alignment the caller wants.
+
+   Use the expression `assemble_name (STREAM, NAME)' to output the
+   name itself; before and after that, output the additional
+   assembler syntax for defining the name, and a newline.
+
+   This macro controls how the assembler definitions of uninitialized
+   common global variables are output.  */
+
+#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED)                  \
+do {                                                                   \
+     fputs ("\t.lcomm ", (STREAM));                                    \
+     assemble_name ((STREAM), (NAME));                                 \
+     fprintf ((STREAM), ",%d\n", (SIZE));                              \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM the assembler definition of a local-common-label named NAME
+   whose size is SIZE bytes.  The variable ROUNDED is the size
+   rounded up to whatever alignment the caller wants.
+
+   Use the expression `assemble_name (STREAM, NAME)' to output the
+   name itself; before and after that, output the additional
+   assembler syntax for defining the name, and a newline.
+
+   This macro controls how the assembler definitions of uninitialized
+   static variables are output.  */
+
+#define ASM_OUTPUT_LABEL(STREAM, NAME)         \
+{                                              \
+  assemble_name (STREAM, NAME);                        \
+  fprintf (STREAM, ":\n");                     \
+}
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM the assembler definition of a label named NAME.  Use the
+   expression `assemble_name (STREAM, NAME)' to output the name
+   itself; before and after that, output the additional assembler
+   syntax for defining the name, and a newline.  */
+
+#undef TYPE_ASM_OP
+#undef SIZE_ASM_OP
+#undef WEAK_ASM_OP
+#define TYPE_ASM_OP    ".type"
+#define SIZE_ASM_OP    ".size"
+#define WEAK_ASM_OP    ".weak"
+/* Define the strings used for the special svr4 .type and .size directives.
+   These strings generally do not vary from one system running svr4 to
+   another, but if a given system (e.g. m88k running svr) needs to use
+   different pseudo-op names for these, they may be overridden in the
+   file which includes this one.  */
+
+
+#undef TYPE_OPERAND_FMT
+#define TYPE_OPERAND_FMT       "@%s"
+/* The following macro defines the format used to output the second
+   operand of the .type assembler directive.  Different svr4 assemblers
+   expect various different forms for this operand.  The one given here
+   is just a default.  You may need to override it in your machine-
+   specific tm.h file (depending upon the particulars of your assembler).  */
+
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL)    \
+do {                                                   \
+     fprintf (FILE, "\t%s\t ", TYPE_ASM_OP);           \
+     assemble_name (FILE, NAME);                       \
+     putc (',', FILE);                                 \
+     fprintf (FILE, TYPE_OPERAND_FMT, "function");     \
+     putc ('\n', FILE);                                        \
+     ASM_OUTPUT_LABEL (FILE, NAME);                    \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM any text necessary for declaring the name NAME of a
+   function which is being defined.  This macro is responsible for
+   outputting the label definition (perhaps using
+   `ASM_OUTPUT_LABEL').  The argument DECL is the `FUNCTION_DECL'
+   tree node representing the function.
+
+   If this macro is not defined, then the function name is defined in
+   the usual manner as a label (by means of `ASM_OUTPUT_LABEL').  */
+
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL)                   \
+  do {                                                                 \
+    if (!flag_inhibit_size_directive)                                  \
+      {                                                                        \
+        char label[256];                                               \
+       static int labelno;                                             \
+       labelno++;                                                      \
+       ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno);            \
+       ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno);               \
+       fprintf (FILE, "\t%s\t ", SIZE_ASM_OP);                         \
+       assemble_name (FILE, (FNAME));                                  \
+        fprintf (FILE, ",");                                           \
+       assemble_name (FILE, label);                                    \
+        fprintf (FILE, "-");                                           \
+       assemble_name (FILE, (FNAME));                                  \
+       putc ('\n', FILE);                                              \
+      }                                                                        \
+  } while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM any text necessary for declaring the size of a function
+   which is being defined.  The argument NAME is the name of the
+   function.  The argument DECL is the `FUNCTION_DECL' tree node
+   representing the function.
+
+   If this macro is not defined, then the function size is not
+   defined.  */
+
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL)                        \
+do {                                                                     \
+      fprintf (FILE, "\t%s\t ", TYPE_ASM_OP);                            \
+      assemble_name (FILE, NAME);                                        \
+      putc (',', FILE);                                                          \
+      fprintf (FILE, TYPE_OPERAND_FMT, "object");                        \
+      putc ('\n', FILE);                                                 \
+      size_directive_output = 0;                                         \
+      if (!flag_inhibit_size_directive && DECL_SIZE (DECL))              \
+       {                                                                 \
+         size_directive_output = 1;                                      \
+         fprintf (FILE, "\t%s\t ", SIZE_ASM_OP);                         \
+         assemble_name (FILE, NAME);                                     \
+         fprintf (FILE, ",%d\n",  int_size_in_bytes (TREE_TYPE (DECL))); \
+    }                                                                    \
+  ASM_OUTPUT_LABEL(FILE, NAME);                                                  \
+} while (0)
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM any text necessary for declaring the name NAME of an
+   initialized variable which is being defined.  This macro must
+   output the label definition (perhaps using `ASM_OUTPUT_LABEL').
+   The argument DECL is the `VAR_DECL' tree node representing the
+   variable.
+
+   If this macro is not defined, then the variable name is defined in
+   the usual manner as a label (by means of `ASM_OUTPUT_LABEL').  */
+
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END)        \
+do {                                                                    \
+     char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0);                  \
+     if (!flag_inhibit_size_directive && DECL_SIZE (DECL)               \
+         && ! AT_END && TOP_LEVEL                                       \
+        && DECL_INITIAL (DECL) == error_mark_node                       \
+        && !size_directive_output)                                      \
+       {                                                                \
+        size_directive_output = 1;                                      \
+        fprintf (FILE, "\t%s\t ", SIZE_ASM_OP);                         \
+        assemble_name (FILE, name);                                     \
+        fprintf (FILE, ",%d\n",  int_size_in_bytes (TREE_TYPE (DECL))); \
+       }                                                                \
+   } while (0)
+/* A C statement (sans semicolon) to finish up declaring a variable
+   name once the compiler has processed its initializer fully and
+   thus has had a chance to determine the size of an array when
+   controlled by an initializer.  This is used on systems where it's
+   necessary to declare something about the size of the object.
+
+   If you don't define this macro, that is equivalent to defining it
+   to do nothing.  */
+
+
+#define ESCAPES \
+"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
+/* A table of bytes codes used by the ASM_OUTPUT_ASCII and
+   ASM_OUTPUT_LIMITED_STRING macros.  Each byte in the table
+   corresponds to a particular byte value [0..255].  For any
+   given byte value, if the value in the corresponding table
+   position is zero, the given character can be output directly.
+   If the table value is 1, the byte must be output as a \ooo
+   octal escape.  If the tables value is anything else, then the
+   byte value should be output as a \ followed by the value
+   in the table.  Note that we can use standard UN*X escape
+   sequences for many control characters, but we don't use
+   \a to represent BEL because some svr4 assemblers (e.g. on
+   the i386) don't know about that.  Also, we don't use \v
+   since some versions of gas, such as 2.2 did not accept it.  */
+
+#define STRING_LIMIT   ((unsigned) 64)
+#define STRING_ASM_OP  ".string"
+/* Some svr4 assemblers have a limit on the number of characters which
+   can appear in the operand of a .string directive.  If your assembler
+   has such a limitation, you should define STRING_LIMIT to reflect that
+   limit.  Note that at least some svr4 assemblers have a limit on the
+   actual number of bytes in the double-quoted string, and that they
+   count each character in an escape sequence as one byte.  Thus, an
+   escape sequence like \377 would count as four bytes.
+
+   If your target assembler doesn't support the .string directive, you
+   should define this to zero.  */
+
+#define ASM_GLOBALIZE_LABEL(STREAM, NAME)      \
+do {                                           \
+  fprintf (STREAM, ".global\t");               \
+  assemble_name (STREAM, NAME);                        \
+  fprintf (STREAM, "\n");                      \
+}                                              \
+while (0)
+     
+/* A C statement (sans semicolon) to output to the stdio stream
+   STREAM some commands that will make the label NAME global; that
+   is, available for reference from other files.  Use the expression
+   `assemble_name (STREAM, NAME)' to output the name itself; before
+   and after that, output the additional assembler syntax for making
+   that name global, and a newline.  */
+
+/* `ASM_WEAKEN_LABEL'
+   A C statement (sans semicolon) to output to the stdio stream
+   STREAM some commands that will make the label NAME weak; that is,
+   available for reference from other files but only used if no other
+   definition is available.  Use the expression `assemble_name
+   (STREAM, NAME)' to output the name itself; before and after that,
+   output the additional assembler syntax for making that name weak,
+   and a newline.
+
+   If you don't define this macro, GNU CC will not support weak
+   symbols and you should not define the `SUPPORTS_WEAK' macro.
+
+   `SUPPORTS_WEAK'
+   A C expression which evaluates to true if the target supports weak
+   symbols.
+
+   If you don't define this macro, `defaults.h' provides a default
+   definition.  If `ASM_WEAKEN_LABEL' is defined, the default
+   definition is `1'; otherwise, it is `0'.  Define this macro if you
+   want to control weak symbol support with a compiler flag such as
+   `-melf'.
+
+   `MAKE_DECL_ONE_ONLY'
+   A C statement (sans semicolon) to mark DECL to be emitted as a
+   public symbol such that extra copies in multiple translation units
+   will be discarded by the linker.  Define this macro if your object
+   file format provides support for this concept, such as the `COMDAT'
+   section flags in the Microsoft Windows PE/COFF format, and this
+   support requires changes to DECL, such as putting it in a separate
+   section.
+
+   `SUPPORTS_WEAK'
+   A C expression which evaluates to true if the target supports
+   one-only semantics.
+
+   If you don't define this macro, `varasm.c' provides a default
+   definition.  If `MAKE_DECL_ONE_ONLY' is defined, the default
+   definition is `1'; otherwise, it is `0'.  Define this macro if you
+   want to control weak symbol support with a compiler flag, or if
+   setting the `DECL_ONE_ONLY' flag is enough to mark a declaration to
+   be emitted as one-only.  */
+
+#define ASM_OUTPUT_INTERNAL_LABEL(STREAM, PREFIX, NUM) \
+fprintf(STREAM, ".%s%d:\n", PREFIX, NUM)
+/* A C statement to output to the stdio stream STREAM a label whose
+   name is made from the string PREFIX and the number NUM.
+
+   It is absolutely essential that these labels be distinct from the
+   labels used for user-level functions and variables.  Otherwise,
+   certain programs will have name conflicts with internal labels.
+
+   It is desirable to exclude internal labels from the symbol table
+   of the object file.  Most assemblers have a naming convention for
+   labels that should be excluded; on many systems, the letter `L' at
+   the beginning of a label has this effect.  You should find out what
+   convention your system uses, and follow it.
+
+   The usual definition of this macro is as follows:
+
+   fprintf (STREAM, "L%s%d:\n", PREFIX, NUM)  */
+
+#define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM)       \
+sprintf (STRING, "*.%s%d", PREFIX, NUM)
+/* A C statement to store into the string STRING a label whose name
+   is made from the string PREFIX and the number NUM.
+
+   This string, when output subsequently by `assemble_name', should
+   produce the output that `ASM_OUTPUT_INTERNAL_LABEL' would produce
+   with the same PREFIX and NUM.
+
+   If the string begins with `*', then `assemble_name' will output
+   the rest of the string unchanged.  It is often convenient for
+   `ASM_GENERATE_INTERNAL_LABEL' to use `*' in this way.  If the
+   string doesn't start with `*', then `ASM_OUTPUT_LABELREF' gets to
+   output the string, and may change it.  (Of course,
+   `ASM_OUTPUT_LABELREF' is also part of your machine description, so
+   you should know what it does on your machine.)  */
+
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10),   \
+  sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+
+/* A C expression to assign to OUTVAR (which is a variable of type
+   `char *') a newly allocated string made from the string NAME and
+   the number NUMBER, with some suitable punctuation added.  Use
+   `alloca' to get space for the string.
+
+   The string will be used as an argument to `ASM_OUTPUT_LABELREF' to
+   produce an assembler label for an internal static variable whose
+   name is NAME.  Therefore, the string must be such as to result in
+   valid assembler code.  The argument NUMBER is different each time
+   this macro is executed; it prevents conflicts between
+   similarly-named internal static variables in different scopes.
+
+   Ideally this string should not be a valid C identifier, to prevent
+   any conflict with the user's own symbols.  Most assemblers allow
+   periods or percent signs in assembler symbols; putting at least
+   one of these between the name and the number will suffice.  */
+
+/* `ASM_OUTPUT_WEAK_ALIAS (STREAM, NAME, VALUE)'
+   A C statement to output to the stdio stream STREAM assembler code
+   which defines (equates) the weak symbol NAME to have the value
+   VALUE.
+
+   Define this macro if the target only supports weak aliases; define
+   ASM_OUTPUT_DEF instead if possible.  */
+
+#define HAS_INIT_SECTION 1
+/* If defined, `main' will not call `__main' as described above.
+   This macro should be defined for systems that control the contents
+   of the init section on a symbol-by-symbol basis, such as OSF/1,
+   and should not be defined explicitly for systems that support
+   `INIT_SECTION_ASM_OP'.  */
+
+#define REGISTER_NAMES {                               \
+  "r0","r1","r2","r3","r4","r5","r6","r7",             \
+    "r8","r9","r10","r11","r12","r13","r14","r15",     \
+    "r16","r17","r18","r19","r20","r21","r22","r23",   \
+    "r24","r25","r26","r27","r28","r29","r30","r31",   \
+    "__SPL__","__SPH__","argL","argH"}
+/* A C initializer containing the assembler's names for the machine
+   registers, each one as a C string constant.  This is what
+   translates register numbers in the compiler into assembler
+   language.  */
+
+#define FINAL_PRESCAN_INSN(insn, operand, nop) final_prescan_insn (insn, operand,nop)
+/* If defined, a C statement to be executed just prior to the output
+   of assembler code for INSN, to modify the extracted operands so
+   they will be output differently.
+
+   Here the argument OPVEC is the vector containing the operands
+   extracted from INSN, and NOPERANDS is the number of elements of
+   the vector which contain meaningful data for this insn.  The
+   contents of this vector are what will be used to convert the insn
+   template into assembler code, so you can change the assembler
+   output by changing the contents of the vector.
+
+   This macro is useful when various assembler syntaxes share a single
+   file of instruction patterns; by defining this macro differently,
+   you can cause a large class of instructions to be output
+   differently (such as with rearranged operands).  Naturally,
+   variations in assembler syntax affecting individual insn patterns
+   ought to be handled by writing conditional output routines in
+   those patterns.
+
+   If this macro is not defined, it is equivalent to a null statement.  */
+
+#define PRINT_OPERAND(STREAM, X, CODE) print_operand (STREAM, X, CODE)
+/* A C compound statement to output to stdio stream STREAM the
+   assembler syntax for an instruction operand X.  X is an RTL
+   expression.
+
+   CODE is a value that can be used to specify one of several ways of
+   printing the operand.  It is used when identical operands must be
+   printed differently depending on the context.  CODE comes from the
+   `%' specification that was used to request printing of the
+   operand.  If the specification was just `%DIGIT' then CODE is 0;
+   if the specification was `%LTR DIGIT' then CODE is the ASCII code
+   for LTR.
+
+   If X is a register, this macro should print the register's name.
+   The names can be found in an array `reg_names' whose type is `char
+   *[]'.  `reg_names' is initialized from `REGISTER_NAMES'.
+
+   When the machine description has a specification `%PUNCT' (a `%'
+   followed by a punctuation character), this macro is called with a
+   null pointer for X and the punctuation character for CODE.  */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '~')
+/* A C expression which evaluates to true if CODE is a valid
+   punctuation character for use in the `PRINT_OPERAND' macro.  If
+   `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no
+   punctuation characters (except for the standard one, `%') are used
+   in this way.  */
+
+#define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X)
+/* A C compound statement to output to stdio stream STREAM the
+   assembler syntax for an instruction operand that is a memory
+   reference whose address is X.  X is an RTL expression.
+
+   On some machines, the syntax for a symbolic address depends on the
+   section that the address refers to.  On these machines, define the
+   macro `ENCODE_SECTION_INFO' to store the information into the
+   `symbol_ref', and then check for it here.  *Note Assembler
+   Format::.  */
+
+#define USER_LABEL_PREFIX ""
+/* `LOCAL_LABEL_PREFIX'
+   `REGISTER_PREFIX'
+   `IMMEDIATE_PREFIX'
+   If defined, C string expressions to be used for the `%R', `%L',
+   `%U', and `%I' options of `asm_fprintf' (see `final.c').  These
+   are useful when a single `md' file must support multiple assembler
+   formats.  In that case, the various `tm.h' files can define these
+   macros differently.  */
+
+#define ASM_OUTPUT_REG_PUSH(STREAM, REGNO)     \
+{                                              \
+  if (REGNO > 31)                              \
+    fatal("regno error in push");              \
+  fprintf (STREAM, "\tpush\tr%d", REGNO);      \
+}
+/* A C expression to output to STREAM some assembler code which will
+   push hard register number REGNO onto the stack.  The code need not
+   be optimal, since this macro is used only when profiling.  */
+
+#define ASM_OUTPUT_REG_POP(STREAM, REGNO)      \
+{                                              \
+  if (REGNO > 31)                              \
+    fatal("regno error in pop");               \
+  fprintf (STREAM, "\tpop\tr%d", REGNO);       \
+}
+/* A C expression to output to STREAM some assembler code which will
+   pop hard register number REGNO off of the stack.  The code need
+   not be optimal, since this macro is used only when profiling.  */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE)                               \
+  fprintf (STREAM, "\t.word pm(.L%d)\n", VALUE);
+/* This macro should be provided on machines where the addresses in a
+   dispatch table are absolute.
+
+   The definition should be a C statement to output to the stdio
+   stream STREAM an assembler pseudo-instruction to generate a
+   reference to a label.  VALUE is the number of an internal label
+   whose definition is output using `ASM_OUTPUT_INTERNAL_LABEL'.  For
+   example,
+
+   fprintf (STREAM, "\t.word L%d\n", VALUE)  */
+
+#define ASM_OUTPUT_CASE_LABEL(STREAM, PREFIX, NUM, TABLE) \
+  progmem_section (), ASM_OUTPUT_INTERNAL_LABEL (STREAM, PREFIX, NUM)
+
+/* `ASM_OUTPUT_CASE_LABEL (STREAM, PREFIX, NUM, TABLE)'
+   Define this if the label before a jump-table needs to be output
+   specially.  The first three arguments are the same as for
+   `ASM_OUTPUT_INTERNAL_LABEL'; the fourth argument is the jump-table
+   which follows (a `jump_insn' containing an `addr_vec' or
+   `addr_diff_vec').
+
+   This feature is used on system V to output a `swbeg' statement for
+   the table.
+
+   If this macro is not defined, these labels are output with
+   `ASM_OUTPUT_INTERNAL_LABEL'.  */
+
+/* `ASM_OUTPUT_CASE_END (STREAM, NUM, TABLE)'
+   Define this if something special must be output at the end of a
+   jump-table.  The definition should be a C statement to be executed
+   after the assembler code for the table is written.  It should write
+   the appropriate code to stdio stream STREAM.  The argument TABLE
+   is the jump-table insn, and NUM is the label-number of the
+   preceding label.
+
+   If this macro is not defined, nothing special is output at the end
+   of the jump-table.  */
+
+#define ASM_OUTPUT_SKIP(STREAM, n)             \
+fprintf (STREAM, "\t.skip %d,0\n", n)
+/* A C statement to output to the stdio stream STREAM an assembler
+   instruction to advance the location counter by NBYTES bytes.
+   Those bytes should be zero when loaded.  NBYTES will be a C
+   expression of type `int'.  */
+
+#define ASM_OUTPUT_ALIGN(STREAM, POWER)
+/* A C statement to output to the stdio stream STREAM an assembler
+   command to advance the location counter to a multiple of 2 to the
+   POWER bytes.  POWER will be a C expression of type `int'.  */
+
+#define CASE_VECTOR_MODE HImode
+/* An alias for a machine mode name.  This is the machine mode that
+   elements of a jump-table should have.  */
+
+#define CASE_VALUES_THRESHOLD 17
+/* `CASE_VALUES_THRESHOLD'
+   Define this to be the smallest number of different values for
+   which it is best to use a jump-table instead of a tree of
+   conditional branches.  The default is four for machines with a
+   `casesi' instruction and five otherwise.  This is best for most
+   machines.  */
+
+#undef WORD_REGISTER_OPERATIONS
+/* Define this macro if operations between registers with integral
+   mode smaller than a word are always performed on the entire
+   register.  Most RISC machines have this property and most CISC
+   machines do not.  */
+
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+/* An alias for a tree code that is the easiest kind of division to
+   compile code for in the general case.  It may be `TRUNC_DIV_EXPR',
+   `FLOOR_DIV_EXPR', `CEIL_DIV_EXPR' or `ROUND_DIV_EXPR'.  These four
+   division operators differ in how they round the result to an
+   integer.  `EASY_DIV_EXPR' is used when it is permissible to use
+   any of those kinds of division and the choice should be made on
+   the basis of efficiency.  */
+
+#define MOVE_MAX 4
+/* The maximum number of bytes that a single instruction can move
+   quickly between memory and registers or between two memory
+   locations.  */
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+/* A C expression which is nonzero if on this machine it is safe to
+   "convert" an integer of INPREC bits to one of OUTPREC bits (where
+   OUTPREC is smaller than INPREC) by merely operating on it as if it
+   had only OUTPREC bits.
+
+   On many machines, this expression can be 1.
+
+   When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for
+   modes for which `MODES_TIEABLE_P' is 0, suboptimal code can result.
+   If this is the case, making `TRULY_NOOP_TRUNCATION' return 0 in
+   such cases may improve things.  */
+
+#define Pmode HImode
+/* An alias for the machine mode for pointers.  On most machines,
+   define this to be the integer mode corresponding to the width of a
+   hardware pointer; `SImode' on 32-bit machine or `DImode' on 64-bit
+   machines.  On some machines you must define this to be one of the
+   partial integer modes, such as `PSImode'.
+
+   The width of `Pmode' must be at least as large as the value of
+   `POINTER_SIZE'.  If it is not equal, you must define the macro
+   `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to
+   `Pmode'.  */
+
+#define FUNCTION_MODE HImode
+/* An alias for the machine mode used for memory references to
+   functions being called, in `call' RTL expressions.  On most
+   machines this should be `QImode'.  */
+     /*                            1        3 */
+#define INTEGRATE_THRESHOLD(DECL) (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2))
+
+/* A C expression for the maximum number of instructions above which
+   the function DECL should not be inlined.  DECL is a
+   `FUNCTION_DECL' node.
+
+   The default definition of this macro is 64 plus 8 times the number
+   of arguments that the function accepts.  Some people think a larger
+   threshold should be used on RISC machines.  */
+
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
+valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
+/* `VALID_MACHINE_DECL_ATTRIBUTE (DECL, ATTRIBUTES, IDENTIFIER, ARGS)'
+   If defined, a C expression whose value is nonzero if IDENTIFIER
+   with arguments ARGS is a valid machine specific attribute for DECL.
+   The attributes in ATTRIBUTES have previously been assigned to DECL.  */
+
+#define VALID_MACHINE_TYPE_ATTRIBUTE(TYPE, ATTRIBUTES, IDENTIFIER, ARGS) \
+     valid_machine_type_attribute(TYPE, ATTRIBUTES, IDENTIFIER, ARGS)
+/* `VALID_MACHINE_TYPE_ATTRIBUTE (TYPE, ATTRIBUTES, IDENTIFIER, ARGS)'
+   If defined, a C expression whose value is nonzero if IDENTIFIER
+   with arguments ARGS is a valid machine specific attribute for TYPE.
+   The attributes in ATTRIBUTES have previously been assigned to TYPE.  */
+
+#define DOLLARS_IN_IDENTIFIERS 0
+/* Define this macro to control use of the character `$' in identifier
+   names.  0 means `$' is not allowed by default; 1 means it is
+   allowed.  1 is the default; there is no need to define this macro
+   in that case.  This macro controls the compiler proper; it does
+   not affect the preprocessor.  */
+
+#define NO_DOLLAR_IN_LABEL 1
+/* Define this macro if the assembler does not accept the character
+   `$' in label names.  By default constructors and destructors in
+   G++ have `$' in the identifiers.  If this macro is defined, `.' is
+   used instead.  */
+
+#define MACHINE_DEPENDENT_REORG(INSN) machine_dependent_reorg (INSN)
+/* In rare cases, correct code generation requires extra machine
+   dependent processing between the second jump optimization pass and
+   delayed branch scheduling.  On those machines, define this macro
+   as a C statement to act on the code starting at INSN.  */
+
+#define GIV_SORT_CRITERION(X, Y)       \
+  if (GET_CODE ((X)->add_val) == CONST_INT             \
+      && GET_CODE ((Y)->add_val) == CONST_INT)         \
+    return INTVAL ((X)->add_val) - INTVAL ((Y)->add_val);
+
+/* `GIV_SORT_CRITERION(GIV1, GIV2)'
+   In some cases, the strength reduction optimization pass can
+   produce better code if this is defined.  This macro controls the
+   order that induction variables are combined.  This macro is
+   particularly useful if the target has limited addressing modes.
+   For instance, the SH target has only positive offsets in
+   addresses.  Thus sorting to put the smallest address first allows
+   the most combinations to be found.  */
+
+/* Define results of standard character escape sequences.  */
+#define TARGET_BELL 007
+#define TARGET_BS 010
+#define TARGET_TAB 011
+#define TARGET_NEWLINE 012
+#define TARGET_VT 013
+#define TARGET_FF 014
+#define TARGET_CR 015
+
+
+
+#define TRAMPOLINE_TEMPLATE(FILE) fatal ("Trampolines not supported\n")
+
+/* Length in units of the trampoline for entering a nested function.  */
+
+#define TRAMPOLINE_SIZE 4
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+   FNADDR is an RTX for the address of the function's pure code.
+   CXT is an RTX for the static chain value for the function.  */
+
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT)                            \
+{                                                                            \
+  emit_move_insn (gen_rtx (MEM, HImode, plus_constant ((TRAMP), 2)), CXT);    \
+  emit_move_insn (gen_rtx (MEM, HImode, plus_constant ((TRAMP), 6)), FNADDR); \
+}
+/* Store in cc_status the expressions
+   that the condition codes will describe
+   after execution of an instruction whose pattern is EXP.
+   Do not alter them if the instruction would not alter the cc's.  */
+
+#define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN)
+
+/* The add insns don't set overflow in a usable way.  */
+#define CC_OVERFLOW_UNUSABLE 01000
+/* The mov,and,or,xor insns don't set carry.  That's ok though as the
+   Z bit is all we need when doing unsigned comparisons on the result of
+   these insns (since they're always with 0).  However, conditions.h has
+   CC_NO_OVERFLOW defined for this purpose.  Rename it to something more
+   understandable.  */
+#define CC_NO_CARRY CC_NO_OVERFLOW
+
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+   for profiling a function entry.  */
+
+#define FUNCTION_PROFILER(FILE, LABELNO)  \
+  fprintf (FILE, "/* profiler %d */", (LABELNO))
+
+/* `FIRST_INSN_ADDRESS'
+   When the `length' insn attribute is used, this macro specifies the
+   value to be assigned to the address of the first insn in a
+   function.  If not specified, 0 is used.  */
+
+#define ADJUST_INSN_LENGTH(INSN, LENGTH) (LENGTH =\
+                                         adjust_insn_length (INSN, LENGTH))
+/* If defined, modifies the length assigned to instruction INSN as a
+   function of the context in which it is used.  LENGTH is an lvalue
+   that contains the initially computed length of the insn and should
+   be updated with the correct length of the insn.  If updating is
+   required, INSN must not be a varying-length insn.
+
+   This macro will normally not be required.  A case in which it is
+   required is the ROMP.  On this machine, the size of an `addr_vec'
+   insn must be increased by two to compensate for the fact that
+   alignment may be required.  */
+
+#define TARGET_MEM_FUNCTIONS
+/* Define this macro if GNU CC should generate calls to the System V
+   (and ANSI C) library functions `memcpy' and `memset' rather than
+   the BSD functions `bcopy' and `bzero'.  */
+
+#define CPP_SPEC "\
+%{!mmcu=*:-DAVR_AT90S8515} \
+%{mmcu=at90s2313:-DAVR_AT90S2313} \
+%{mmcu=at90s2323:-DAVR_AT90S2323} \
+%{mmcu=at90s2333:-DAVR_AT90S2333} \
+%{mmcu=at90s2343:-DAVR_AT90S2343} \
+%{mmcu=attiny22:-DAVR_ATtiny22} \
+%{mmcu=at90s4433:-DAVR_AT90S4433} \
+%{mmcu=at90s4414:-DAVR_AT90S4414} \
+%{mmcu=at90s4434:-DAVR_AT90S4434} \
+%{mmcu=at90s8515:-DAVR_AT90S8515} \
+%{mmcu=at90s8535:-DAVR_AT90S8535} \
+%{mmcu=atmega603:-DAVR_ATmega603} \
+%{mmcu=atmega103:-DAVR_ATmega103} \
+%{mint8:-D__SIZE_TYPE__=long\\ unsigned\\ int -D__PTRDIFF_TYPE__=long -D__INT_MAX__=127} \
+%{!mint*:-D__SIZE_TYPE__=unsigned\\ int -D__PTRDIFF_TYPE__=int -D__INT_MAX__=32767} \
+%{posix:-D_POSIX_SOURCE}"
+/* A C string constant that tells the GNU CC driver program options to
+   pass to CPP.  It can also specify how to translate options you
+   give to GNU CC into options for GNU CC to pass to the CPP.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#define NO_BUILTIN_SIZE_TYPE
+/* If this macro is defined, the preprocessor will not define the
+   builtin macro `__SIZE_TYPE__'.  The macro `__SIZE_TYPE__' must
+   then be defined by `CPP_SPEC' instead.
+
+   This should be defined if `SIZE_TYPE' depends on target dependent
+   flags which are not accessible to the preprocessor.  Otherwise, it
+   should not be defined.  */
+
+#define NO_BUILTIN_PTRDIFF_TYPE
+/* If this macro is defined, the preprocessor will not define the
+   builtin macro `__PTRDIFF_TYPE__'.  The macro `__PTRDIFF_TYPE__'
+   must then be defined by `CPP_SPEC' instead.
+
+   This should be defined if `PTRDIFF_TYPE' depends on target
+   dependent flags which are not accessible to the preprocessor.
+   Otherwise, it should not be defined.
+
+   `SIGNED_CHAR_SPEC'
+   A C string constant that tells the GNU CC driver program options to
+   pass to CPP.  By default, this macro is defined to pass the option
+   `-D__CHAR_UNSIGNED__' to CPP if `char' will be treated as
+   `unsigned char' by `cc1'.
+
+   Do not define this macro unless you need to override the default
+   definition.  */
+
+#define CC1_SPEC "%{!mmcu*:-mmcu=at90s8515} %{profile:-p}"
+/* A C string constant that tells the GNU CC driver program options to
+   pass to `cc1'.  It can also specify how to translate options you
+   give to GNU CC into options for GNU CC to pass to the `cc1'.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#define ASM_SPEC ""
+/* A C string constant that tells the GNU CC driver program options to
+   pass to the assembler.  It can also specify how to translate
+   options you give to GNU CC into options for GNU CC to pass to the
+   assembler.  See the file `sun3.h' for an example of this.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#define ASM_FINAL_SPEC ""
+/* A C string constant that tells the GNU CC driver program how to
+   run any programs which cleanup after the normal assembler.
+   Normally, this is not needed.  See the file `mips.h' for an
+   example of this.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#define LINK_SPEC "\
+%{!mmcu*:-m avr85xx} \
+%{mmcu=atmega603:-m avrmega603} \
+%{mmcu=atmega103:-m avrmega103} \
+%{mmcu=at90s2313:-m avr23xx} \
+%{mmcu=at90s2323:-m avr23xx} \
+%{mmcu=attiny22:-m avr23xx} \
+%{mmcu=at90s2333:-m avr23xx} \
+%{mmcu=at90s2343:-m avr23xx} \
+%{mmcu=at90s4433:-m avr4433} \
+%{mmcu=at90s4414:-m avr44x4} \
+%{mmcu=at90s4434:-m avr44x4} \
+%{mmcu=at90s8535:-m avr85xx} \
+%{mmcu=at90s8515:-m avr85xx}"
+
+/* A C string constant that tells the GNU CC driver program options to
+   pass to the linker.  It can also specify how to translate options
+   you give to GNU CC into options for GNU CC to pass to the linker.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#define LIB_SPEC "\
+%{!mmcu*|mmcu=at90s*|mmcu=attiny22: -lc} \
+%{mmcu=atmega*: -lc-mega}"
+/* Another C string constant used much like `LINK_SPEC'.  The
+   difference between the two is that `LIB_SPEC' is used at the end
+   of the command given to the linker.
+
+   If this macro is not defined, a default is provided that loads the
+   standard C library from the usual place.  See `gcc.c'.  */
+
+#define LIBGCC_SPEC "\
+%{mmcu=atmega*:-lgcc} \
+%{!mmcu*|mmcu=at90s*|mmcu=attiny22:-lgcc}"
+/* Another C string constant that tells the GNU CC driver program how
+   and when to place a reference to `libgcc.a' into the linker
+   command line.  This constant is placed both before and after the
+   value of `LIB_SPEC'.
+
+   If this macro is not defined, the GNU CC driver provides a default
+   that passes the string `-lgcc' to the linker unless the `-shared'
+   option is specified.  */
+
+#define STARTFILE_SPEC "%(crt_binutils)"
+/* Another C string constant used much like `LINK_SPEC'.  The
+   difference between the two is that `STARTFILE_SPEC' is used at the
+   very beginning of the command given to the linker.
+
+   If this macro is not defined, a default is provided that loads the
+   standard C startup file from the usual place.  See `gcc.c'.  */
+
+#define ENDFILE_SPEC ""
+/* Another C string constant used much like `LINK_SPEC'.  The
+   difference between the two is that `ENDFILE_SPEC' is used at the
+   very end of the command given to the linker.
+
+   Do not define this macro if it does not need to do anything.  */
+
+#define CRT_BINUTILS_SPECS "\
+%{!mmcu*:gcrt1-8515.o%s} \
+%{mmcu=atmega603:gcrt1-mega603.o%s} \
+%{mmcu=atmega103:gcrt1-mega103.o%s} \
+%{mmcu=at90s2313:gcrt1-2313.o%s} \
+%{mmcu=at90s2323:gcrt1-2323.o%s} \
+%{mmcu=attiny22:gcrt1-tiny22.o%s} \
+%{mmcu=at90s2333:gcrt1-2333.o%s} \
+%{mmcu=at90s2343:gcrt1-2343.o%s} \
+%{mmcu=at90s4433:gcrt1-4433.o%s} \
+%{mmcu=at90s4414:gcrt1-4414.o%s} \
+%{mmcu=at90s4434:gcrt1-4434.o%s} \
+%{mmcu=at90s8535:gcrt1-8535.o%s} \
+%{mmcu=at90s8515:gcrt1-8515.o%s}"
+
+#define EXTRA_SPECS                            \
+{"crt_binutils", CRT_BINUTILS_SPECS},
+/* Define this macro to provide additional specifications to put in
+   the `specs' file that can be used in various specifications like
+   `CC1_SPEC'.
+
+   The definition should be an initializer for an array of structures,
+   containing a string constant, that defines the specification name,
+   and a string constant that provides the specification.
+
+   Do not define this macro if it does not need to do anything.
+
+   `EXTRA_SPECS' is useful when an architecture contains several
+   related targets, which have various `..._SPECS' which are similar
+   to each other, and the maintainer would like one central place to
+   keep these definitions.
+
+   For example, the PowerPC System V.4 targets use `EXTRA_SPECS' to
+   define either `_CALL_SYSV' when the System V calling sequence is
+   used or `_CALL_AIX' when the older AIX-based calling sequence is
+   used.
+
+   The `config/rs6000/rs6000.h' target file defines:
+
+   #define EXTRA_SPECS \
+   { "cpp_sysv_default", CPP_SYSV_DEFAULT },
+
+   #define CPP_SYS_DEFAULT ""
+
+   The `config/rs6000/sysv.h' target file defines:
+   #undef CPP_SPEC
+   #define CPP_SPEC \
+   "%{posix: -D_POSIX_SOURCE } \
+   %{mcall-sysv: -D_CALL_SYSV } %{mcall-aix: -D_CALL_AIX } \
+   %{!mcall-sysv: %{!mcall-aix: %(cpp_sysv_default) }} \
+   %{msoft-float: -D_SOFT_FLOAT} %{mcpu=403: -D_SOFT_FLOAT}"
+
+   #undef CPP_SYSV_DEFAULT
+   #define CPP_SYSV_DEFAULT "-D_CALL_SYSV"
+
+   while the `config/rs6000/eabiaix.h' target file defines
+   `CPP_SYSV_DEFAULT' as:
+
+   #undef CPP_SYSV_DEFAULT
+   #define CPP_SYSV_DEFAULT "-D_CALL_AIX"  */
+
+/* This is undefined macro for collect2 disabling */
+#define LINKER_NAME "ld"
+
+#define TEST_HARD_REG_CLASS(CLASS, REGNO) \
+  TEST_HARD_REG_BIT (reg_class_contents[ (int) (CLASS)], REGNO)
+
+/* Note that the other files fail to use these
+   in some of the places where they should.  */
+
+#if defined(__STDC__) || defined(ALMOST_STDC)
+#define AS2(a,b,c) #a " " #b "," #c
+#define AS2C(b,c) " " #b "," #c
+#define AS3(a,b,c,d) #a " " #b "," #c "," #d
+#define AS1(a,b) #a " " #b
+#else
+#define AS1(a,b) "a    b"
+#define AS2(a,b,c) "a  b,c"
+#define AS2C(b,c) " b,c"
+#define AS3(a,b,c,d) "a        b,c,d"
+#endif
+#define OUT_AS1(a,b) output_asm_insn (AS1(a,b), operands)
+#define OUT_AS2(a,b,c) output_asm_insn (AS2(a,b,c), operands)
+#define CR_TAB "\n\t"
+
+/* Define this macro as a C statement that declares additional library
+   routines renames existing ones. `init_optabs' calls this macro
+   after initializing all the normal library routines.  */
+
+#define INIT_TARGET_OPTABS                             \
+{                                                      \
+  smul_optab->handlers[(int) QImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_mulqi3");          \
+                                                       \
+  sdiv_optab->handlers[(int) QImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_divqi3");          \
+                                                       \
+  smod_optab->handlers[(int) QImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_modqi3");          \
+                                                       \
+  udiv_optab->handlers[(int) QImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_udivqi3");         \
+                                                       \
+  umod_optab->handlers[(int) QImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_umodqi3");         \
+                                                       \
+  smul_optab->handlers[(int) HImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_mulhi3");          \
+                                                       \
+  sdiv_optab->handlers[(int) HImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_divhi3");          \
+                                                       \
+  smod_optab->handlers[(int) HImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_modhi3");          \
+                                                       \
+  udiv_optab->handlers[(int) HImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_udivhi3");         \
+                                                       \
+  umod_optab->handlers[(int) HImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_umodhi3");         \
+                                                       \
+  smul_optab->handlers[(int) SImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_mulsi3");          \
+                                                       \
+  sdiv_optab->handlers[(int) SImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_divsi3");          \
+                                                       \
+  smod_optab->handlers[(int) SImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_modsi3");          \
+                                                       \
+  udiv_optab->handlers[(int) SImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_udivsi3");         \
+                                                       \
+  umod_optab->handlers[(int) SImode].libfunc           \
+    = gen_rtx (SYMBOL_REF, Pmode, "_umodsi3");         \
+  avr_init_once();                                     \
+}
+
+/* Temporary register r0 */
+#define TMP_REGNO 0
+
+/* zero register r1 */
+#define ZERO_REGNO 1
+
+extern struct rtx_def *tmp_reg_rtx;
+extern struct rtx_def *zero_reg_rtx;
+
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
+
+/* Define to use software floating point emulator for REAL_ARITHMETIC and
+   decimal <-> binary conversion. */
+#define REAL_ARITHMETIC
+
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#define DBX_REGISTER_NUMBER(r) (r)
+
+/* Get the standard ELF stabs definitions.  */
+#include "dbxelf.h"
+
+#undef ASM_IDENTIFY_GCC
+#define ASM_IDENTIFY_GCC(FILE)                         \
+do                                                     \
+  {                                                    \
+    if (write_symbols != DBX_DEBUG)                    \
+      fputs ("gcc2_compiled.:\n", FILE);               \
+  }                                                    \
+while (0)
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
new file mode 100644 (file)
index 0000000..f90db47
--- /dev/null
@@ -0,0 +1,1903 @@
+;; -*- Mode: Scheme -*-
+;;   Machine description for GNU compiler,
+;;   for ATMEL AVR micro controllers.
+;;   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+;;   Contributed by Denis Chertykov (denisc@overta.ru)
+
+;; This file is part of GNU CC.
+
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING.  If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;; Condition code settings.
+(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber"
+  (const_string "none"))
+
+(define_attr "type" "branch,branch1,arith"
+  (const_string "arith"))
+
+;; The size of instructions in bytes.
+;; XXX may depend from "cc"
+
+(define_attr "length" ""
+  (cond [(eq_attr "type" "branch")
+         (if_then_else (and (ge (minus (pc) (match_dup 0))
+                                (const_int -63))
+                            (le (minus (pc) (match_dup 0))
+                                (const_int 62)))
+                       (const_int 1)
+                       (if_then_else (and (ge (minus (pc) (match_dup 0))
+                                              (const_int -2045))
+                                          (le (minus (pc) (match_dup 0))
+                                              (const_int 2045)))
+                                     (const_int 2)
+                                     (const_int 2)))
+         (eq_attr "type" "branch1")
+         (if_then_else (and (ge (minus (pc) (match_dup 0))
+                                (const_int -62))
+                            (le (minus (pc) (match_dup 0))
+                                (const_int 61)))
+                       (const_int 2)
+                       (if_then_else (and (ge (minus (pc) (match_dup 0))
+                                              (const_int -2044))
+                                          (le (minus (pc) (match_dup 0))
+                                              (const_int 2043)))
+                                     (const_int 3)
+                                     (const_int 3)))]
+        (const_int 2)))
+
+(define_insn "*pop1"
+  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 1)))]
+  ""
+  "pop __tmp_reg__"
+  [(set_attr "length" "1")])
+
+(define_insn "*pop2"
+  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 2)))]
+  ""
+  "pop __tmp_reg__
+       pop __tmp_reg__"
+  [(set_attr "length" "2")])
+
+(define_insn "*pop3"
+  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 3)))]
+  ""
+  "pop __tmp_reg__
+       pop __tmp_reg__
+       pop __tmp_reg__"
+  [(set_attr "length" "3")])
+
+(define_insn "*pop4"
+  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 4)))]
+  ""
+  "pop __tmp_reg__
+       pop __tmp_reg__
+       pop __tmp_reg__
+       pop __tmp_reg__"
+  [(set_attr "length" "4")])
+
+(define_insn "*pop5"
+  [(set (reg:HI 32) (plus:HI (reg:HI 32) (const_int 5)))]
+  ""
+  "pop __tmp_reg__
+       pop __tmp_reg__
+       pop __tmp_reg__
+       pop __tmp_reg__
+       pop __tmp_reg__"
+  [(set_attr "length" "5")])
+
+(define_insn "*pushqi"
+  [(set (mem:QI (post_dec (reg:HI 32)))
+        (match_operand:QI 0 "nonmemory_operand" "r,L"))]
+  "(operands[0] == const0_rtx || register_operand (operands[0], QImode))"
+  "@
+       push %0
+       push __zero_reg__"
+  [(set_attr "length" "1,1")])
+
+
+(define_insn "*pushhi"
+  [(set (mem:HI (post_dec (reg:HI 32)))
+        (match_operand:HI 0 "nonmemory_operand" "r,L"))]
+  "(operands[0] == const0_rtx || register_operand (operands[0], HImode))"
+  "@
+       push %B0\;push %A0
+       push __zero_reg__\;push __zero_reg__"
+  [(set_attr "length" "2,2")])
+
+(define_insn "*pushsi"
+  [(set (mem:SI (post_dec (reg:HI 32)))
+        (match_operand:SI 0 "nonmemory_operand" "r,L"))]
+  "(operands[0] == const0_rtx || register_operand (operands[0], SImode))"
+  "@
+       push %D0\;push %C0\;push %B0\;push %A0
+       push __zero_reg__\;push __zero_reg__\;push __zero_reg__\;push __zero_reg__"
+  [(set_attr "length" "4,4")])
+
+(define_insn "*pushsf"
+  [(set (mem:SF (post_dec (reg:HI 32)))
+        (match_operand:SF 0 "register_operand" "r"))]
+  ""
+  "push %D0
+       push %C0
+       push %B0
+       push %A0"
+  [(set_attr "length" "4")])
+
+(define_insn "*mov_r_sp"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+        (reg:HI 32))]
+  ""
+  "in %A0,__SP_L__
+       in %B0,__SP_H__"
+  [(set_attr "length" "2")])
+
+(define_insn "*mov_sp_r"
+  [(set (reg:HI 32)
+        (match_operand:HI 0 "register_operand" "r"))]
+  "!TARGET_NO_INTERRUPTS"
+  "in __tmp_reg__,__SREG__
+       cli
+       out __SP_L__,%A0
+       out __SREG__,__tmp_reg__
+       out __SP_H__,%B0"
+  [(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"
+  [(set_attr "length" "2")])
+
+;;========================================================================
+;; move byte
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "")
+       (match_operand:QI 1 "general_operand" ""))]
+  ""
+  "
+{
+  /* One of the ops has to be in a register */
+  if (!register_operand(operand0, QImode)
+      && ! (register_operand(operand1, QImode) || const0_rtx == operand1))
+    {
+      operands[1] = copy_to_mode_reg(QImode, operand1);
+    }
+ }"); 
+
+(define_insn "*movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,d,Qm,r,q")
+       (match_operand:QI 1 "general_operand"      "r,L,i,rL,Qm,r"))]
+  "(register_operand (operands[0],QImode)
+    || register_operand (operands[1], QImode) || const0_rtx == operands[1])"
+  "*{
+    switch (which_alternative)
+      {
+      case 0:
+       return AS2 (mov, %0,%1);
+      case 1:
+       return AS1 (clr, %0);
+      case 2:
+       return AS2 (ldi, %0,lo8(%1));
+      case 3:
+        {
+          rtx save1=NULL;
+          if (operands[1] == const0_rtx)
+            {
+              save1 = operands[1];
+              operands[1] = zero_reg_rtx;
+            }
+          output_asm_insn (out_movqi_mr_r (insn,operands,NULL), operands);
+          if (save1)
+            operands[1] = save1;
+        }
+        return \"\";
+      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));
+      }
+}"
+  [(set_attr "length" "1,1,1,5,5,4")
+   (set_attr "cc" "none,clobber,none,clobber,clobber,none")])
+
+;;============================================================================
+;; move word (16 bit)
+
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "")
+        (match_operand:HI 1 "general_operand"       ""))]
+  ""
+  "
+{
+   /* One of the ops has to be in a register */
+  if (!register_operand(operand0, HImode)
+      && !(register_operand(operand1, HImode)  || const0_rtx == operands[1]))
+    {
+      operands[1] = copy_to_mode_reg(HImode, operand1);
+    }
+}")
+
+(define_insn "*movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,d,r,m")
+        (match_operand:HI 1 "general_operand"       "r,L,i,m,rL"))]
+  "(register_operand (operands[0],HImode)
+    || register_operand (operands[1],HImode) || const0_rtx == operands[1])"
+  "*{
+  rtx link;
+  switch (which_alternative)
+    {
+    case 0: /* mov r,r */
+      if (true_regnum (operands[0]) > true_regnum (operands[1]))
+        return (AS2 (mov,%B0,%B1) CR_TAB
+               AS2 (mov,%A0,%A1));
+      else
+        return (AS2 (mov,%A0,%A1) CR_TAB
+               AS2 (mov,%B0,%B1));
+    case 1:  /* mov r,L */
+      return (AS1 (clr,%A0) CR_TAB
+             AS1 (clr,%B0));
+    case 2: /* mov r,d */
+      if (operands[1] == const1_rtx
+          && (link = find_reg_note (insn, REG_WAS_0, 0))
+         /* Make sure the insn that stored the 0 is still present.  */
+         && ! INSN_DELETED_P (XEXP (link, 0))
+         && GET_CODE (XEXP (link, 0)) != NOTE
+         /* Make sure cross jumping didn't happen here.  */
+         && no_labels_between_p (XEXP (link, 0), insn)
+         /* Make sure the reg hasn't been clobbered.  */
+         && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
+      /* Fastest way to change a 0 to a 1.  */
+        return AS1 (inc,%A0 ; reg_was_0);
+      return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
+             AS2 (ldi,%B0,hi8(%1)));
+    case 3: /* mov r,m*/
+      return out_movhi_r_mr (insn, operands, NULL);
+    case 4: /* mov m,r*/
+        {
+          rtx save1=NULL;
+          if (operands[1] == const0_rtx)
+            {
+              save1 = operands[1];
+              operands[1] = zero_reg_rtx;
+            }
+          output_asm_insn (out_movhi_mr_r (insn,operands,NULL), operands);
+          if (save1)
+            operands[1] = save1;
+        }
+        return \"\";
+    }
+}"
+  [(set_attr "length" "2,2,2,4,4")
+   (set_attr "cc" "none,set_zn,none,clobber,clobber")])
+
+;;==========================================================================
+;; move double word (32 bit)
+
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+        (match_operand:SI 1 "general_operand"  ""))]
+  ""
+  "
+{
+  /* One of the ops has to be in a register.  */
+  if (!register_operand (operand0, SImode)
+      && !(register_operand (operand1, SImode) || const0_rtx == operand1))
+    {
+      operands[1] = copy_to_mode_reg (SImode, operand1);
+    }
+}")
+
+(define_insn "*movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,d,r,Qm")
+        (match_operand:SI 1 "general_operand"      "r,L,i,Qm,rL"))]
+  "(register_operand (operands[0],SImode)
+    || register_operand (operands[1],SImode) || const0_rtx == operands[1])"
+  "* return output_movsisf (insn, operands, which_alternative);"
+  [(set_attr "length" "4,4,4,8,8")
+   (set_attr "cc" "none,set_zn,none,clobber,clobber")])
+
+;; fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+;; move floating point numbers (32 bit)
+
+(define_expand "movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "")
+        (match_operand:SF 1 "general_operand"  ""))]
+  ""
+  "
+{
+  /* One of the ops has to be in a register.  */
+  if (!register_operand (operand1, SFmode)
+      && !register_operand (operand0, SFmode))
+    {
+      operands[1] = copy_to_mode_reg (SFmode, operand1);
+    }
+}")
+
+(define_insn "*movsf"
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,d,r,Qm")
+        (match_operand:SF 1 "general_operand"      "r,G,F,Qm,r"))]
+  "register_operand (operands[0], SFmode)
+   || register_operand (operands[1], SFmode)"
+  "* return output_movsisf (insn, operands, which_alternative);"
+  [(set_attr "length" "4,4,4,8,8")
+   (set_attr "cc" "none,set_zn,none,clobber,clobber")])
+
+;;=========================================================================
+;; move string (like memcpy)
+
+(define_expand "movstrhi"
+  [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+                  (match_operand:BLK 1 "memory_operand" ""))
+             (use (match_operand:HI 2 "const_int_operand" ""))
+             (use (match_operand:HI 3 "const_int_operand" ""))
+             (clobber (match_dup 4))
+             (clobber (match_dup 5))
+             (clobber (match_dup 6))])]
+  ""
+  "{
+  rtx addr0, addr1;
+  int cnt8;
+
+  if (GET_CODE (operands[2]) != CONST_INT)
+    FAIL;
+  cnt8 = byte_immediate_operand (operands[2], GET_MODE (operands[2]));
+  operands[2] = copy_to_mode_reg (cnt8 ? QImode : HImode, operands[2]);
+  operands[4] = operands[2];
+
+  addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+  addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+
+  operands[5] = addr0;
+  operands[6] = addr1;
+
+  operands[0] = gen_rtx (MEM, BLKmode, addr0);
+  operands[1] = gen_rtx (MEM, BLKmode, addr1);
+}")
+
+(define_insn "*movstrqi_insn"
+  [(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
+       (mem:BLK (match_operand:HI 1 "register_operand" "e")))
+   (use (match_operand:QI 2 "register_operand" "r"))
+   (use (match_operand:QI 3 "const_int_operand" "i"))
+   (clobber (match_dup 2))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))]
+  ""
+  "
+       ld __tmp_reg__,%a1+
+       st %a0+,__tmp_reg__
+       dec %2
+       brne _PC_-8"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*movstrhi"
+  [(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
+       (mem:BLK (match_operand:HI 1 "register_operand" "e,e")))
+   (use (match_operand:HI 2 "register_operand" "!w,d"))
+   (use (match_operand:HI 3 "const_int_operand" ""))
+   (clobber (match_dup 2))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))]
+  ""
+  "*{
+     if (which_alternative==0)
+       return (AS2 (ld,__tmp_reg__,%a1+) CR_TAB
+              AS2 (st,%a0+,__tmp_reg__)  CR_TAB
+              AS2 (sbiw,%A2,1) CR_TAB
+              AS1 (brne,_PC_-8));
+     else
+       return (AS2 (ld,__tmp_reg__,%a1+) CR_TAB
+              AS2 (st,%a0+,__tmp_reg__)  CR_TAB
+              AS2 (subi,%A2,1) CR_TAB
+              AS2 (sbci,%B2,0) CR_TAB
+              AS1 (brne,_PC_-10));
+}"
+  [(set_attr "length" "4,5")
+   (set_attr "cc" "clobber,clobber")])
+
+;; =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0 =0
+;; memset (%0, 0, %1)
+
+(define_expand "clrstrhi"
+  [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
+                  (const_int 0))
+             (use (match_operand:HI 1 "const_int_operand" ""))
+             (use (match_operand:HI 2 "const_int_operand" "n"))
+             (clobber (match_dup 3))
+             (clobber (match_dup 4))])]
+  ""
+  "{
+  rtx addr0;
+  int cnt8;
+
+  if (GET_CODE (operands[1]) != CONST_INT)
+    FAIL;
+
+  cnt8 = byte_immediate_operand (operands[1], GET_MODE (operands[1]));
+  operands[1] = copy_to_mode_reg (cnt8 ? QImode : HImode, operands[1]);
+  operands[3] = operands[1];
+
+  addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+  operands[4] = addr0;
+  
+  operands[0] = gen_rtx (MEM, BLKmode, addr0);
+}")
+
+(define_insn "*clrstrqi"
+  [(set (mem:BLK (match_operand:HI 0 "register_operand" "e"))
+       (const_int 0))
+   (use (match_operand:QI 1 "register_operand" "r"))
+   (use (match_operand:QI 2 "const_int_operand" "n"))
+   (clobber (match_dup 1))
+   (clobber (match_dup 0))]
+  ""
+  "
+       st %a0+,__zero_reg__
+        dec %1
+       brne _PC_-6"
+  [(set_attr "length" "3")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*clrstrhi"
+  [(set (mem:BLK (match_operand:HI 0 "register_operand" "e,e"))
+       (const_int 0))
+   (use (match_operand:HI 1 "register_operand" "!w,d"))
+   (use (match_operand:HI 2 "const_int_operand" "n,n"))
+   (clobber (match_dup 1))
+   (clobber (match_dup 0))]
+  ""
+  "*{
+     if (which_alternative==0)
+       return (AS2 (st,%a0+,__zero_reg__) CR_TAB
+              AS2 (sbiw,%A1,1) CR_TAB
+              AS1 (brne,_PC_-6));
+     else
+       return (AS2 (st,%a0+,__zero_reg__) CR_TAB
+              AS2 (subi,%A1,1) CR_TAB
+              AS2 (sbci,%B1,0) CR_TAB
+              AS1 (brne,_PC_-8));
+}"
+  [(set_attr "length" "3,4")
+   (set_attr "cc" "clobber,clobber")])
+
+(define_expand "strlenhi"
+    [(parallel
+      [(set (match_dup 4)
+           (unspec:HI [(match_operand:BLK 1 "memory_operand" "")
+                       (match_operand:QI 2 "const_int_operand" "")
+                       (match_operand:HI 3 "immediate_operand" "")] 0))
+       (clobber (match_dup 6))])
+     (set (match_dup 4) (plus:HI (match_dup 4)
+                                (const_int -1)))
+     (set (match_operand:HI 0 "register_operand" "")
+         (minus:HI (match_dup 4)
+                   (match_dup 5)))]
+   ""
+   "{
+  if (! (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0))
+    FAIL;
+  operands[6] = copy_to_mode_reg (Pmode, XEXP (operands[1],0));
+  operands[1] = gen_rtx (MEM, BLKmode, operands[6]); 
+  operands[5] = operands[6];
+  operands[4] = gen_reg_rtx (HImode);
+}")
+
+(define_insn "*strlenhi"
+  [(set (match_operand:HI 0 "register_operand" "=e")
+       (unspec:HI [(mem:BLK (match_operand:HI 1 "register_operand" "%0"))
+                   (const_int 0)
+                   (match_operand:HI 2 "immediate_operand" "i")] 0))
+   (clobber (match_dup 1))]
+  ""
+  "ld __tmp_reg__,%a0+
+       tst __tmp_reg__
+       brne _PC_-6"
+  [(set_attr "length" "3")
+   (set_attr "cc" "clobber")])
+
+;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+; add bytes
+
+(define_insn "addqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,d,r,r")
+        (plus:QI (match_operand:QI 1 "register_operand" "%0,0,0,0")
+                 (match_operand:QI 2 "nonmemory_operand" "r,i,P,N")))]
+  ""
+  "@
+       add %0,%2
+       subi %0,lo8(-(%2))
+       inc %0
+       dec %0"
+  [(set_attr "length" "1,1,1,1")
+   (set_attr "cc" "set_czn,set_czn,set_zn,set_zn")])
+
+
+(define_expand "addhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (plus:HI (match_operand:HI 1 "register_operand" "")
+                (match_operand:HI 2 "nonmemory_operand" "")))]
+  ""
+  "
+{
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      short tmp = INTVAL (operands[2]);
+      operands[2] = GEN_INT(tmp);
+    }
+ if (! (reload_completed | reload_in_progress))
+   {
+     if (REGNO (operands[0]) != REGNO (operands[1])
+        && REGNO (operands[0]) != REGNO (operands[2])&&0)
+       {
+        emit_move_insn (operands[0], operands[1]);
+        operands[1] = operands[0];
+       }
+   }
+}")
+
+
+(define_insn "*addhi3_zero_extend"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (zero_extend:HI
+                 (match_operand:QI 1 "register_operand" "r"))
+                (match_operand:HI 2 "register_operand" "0")))]
+  ""
+  "add %A0,%1
+       adc %B0,__zero_reg__"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_n")])
+
+(define_insn "*addhi3_zero_extend1"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (match_operand:HI 1 "register_operand" "%0")
+                (zero_extend:HI
+                 (match_operand:QI 2 "register_operand" "r"))))]
+  ""
+  "add %A0,%2
+       adc %B0,__zero_reg__"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_n")])
+
+(define_insn "*addhi3_zero_extend2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI
+        (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+        (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+  ""
+  "add %0,%2
+       mov %B0,__zero_reg__
+       adc %B0,__zero_reg__"
+  [(set_attr "length" "3")
+   (set_attr "cc" "set_n")])
+
+(define_insn "*addhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,!w,!w,d,r,r")
+       (plus:HI
+        (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
+        (match_operand:HI 2 "nonmemory_operand" "r,I,J,i,P,N")))]
+  ""
+  "@
+       add %A0,%A2\;adc %B0,%B2
+       adiw %A0,%2
+       sbiw %A0,%n2
+       subi %A0,lo8(-(%2))\;sbci %B0,hi8(-(%2))
+       sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__
+       sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__"
+  [(set_attr "length" "2,1,1,2,3,3")
+   (set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")])
+
+(define_insn "addsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,!w,!w,d,r,r,&*!w,&*!w")
+         (plus:SI
+          (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,r")
+          (match_operand:SI 2 "nonmemory_operand" "r,I,J,i,P,N,#I,#J")))]
+  ""
+  "@
+       add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2
+       adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
+       sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__
+       subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))
+       sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
+       sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__
+       mov %A0,%A1\;mov %B0,%B1\;mov %C0,%C1\;mov %D0,%D1\;adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__
+       mov %A0,%A1\;mov %B0,%B1\;mov %C0,%C1\;mov %D0,%D1\;sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__"
+  [(set_attr "length" "4,3,3,4,5,5,7,7")
+   (set_attr "cc" "set_n,set_n,set_czn,set_czn,set_n,set_n,set_n,set_czn")])
+
+;-----------------------------------------------------------------------------
+; sub bytes
+(define_insn "subqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,d")
+        (minus:QI (match_operand:QI 1 "register_operand" "0,0")
+                  (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "@
+       sub %0,%2
+       subi %0,lo8(%2)"
+  [(set_attr "length" "1,1")
+   (set_attr "cc" "set_czn,set_czn")])
+
+(define_insn "subhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,d")
+        (minus:HI (match_operand:HI 1 "register_operand" "0,0")
+                 (match_operand:HI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "@
+       sub %A0,%A2\;sbc %B0,%B2
+       subi %A0,lo8(%2)\;sbci %B0,hi8(%2)"
+  [(set_attr "length" "2,2")
+   (set_attr "cc" "set_czn,set_czn")])
+
+(define_insn "subsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,d")
+        (minus:SI (match_operand:SI 1 "register_operand" "0,0")
+                 (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "@
+       sub %0,%2\;sbc %B0,%B2\;sbc %C0,%C2\;sbc %D0,%D2
+       subi %A0,lo8(%2)\;sbci %B0,hi8(%2)\;sbci %C0,hlo8(%2)\;sbci %D0,hhi8(%2)"
+  [(set_attr "length" "4,4")
+   (set_attr "cc" "set_czn,set_czn")])
+
+;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+; and
+
+(define_insn "andqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,d")
+        (and:QI (match_operand:QI 1 "register_operand" "%0,0")
+                (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "@
+       and %0,%2
+       andi %0,lo8(%2)"
+  [(set_attr "length" "1,1")
+   (set_attr "cc" "set_zn,set_zn")])
+
+(define_insn "andhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,d,r")
+         (and:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+                 (match_operand:HI 2 "nonmemory_operand" "r,i,M")))
+   (clobber (match_scratch:QI 3 "=X,X,&d"))]
+  ""
+  "*{
+  if (which_alternative==0)
+    return (AS2 (and,%A0,%A2) CR_TAB
+           AS2 (and,%B0,%B2));
+  else if (which_alternative==1)
+    {
+      if (GET_CODE (operands[2]) == CONST_INT)
+        {
+         int mask = INTVAL (operands[2]);
+         if ((mask & 0xff) != 0xff)
+           output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
+         if ((mask & 0xff00) != 0xff00)
+           output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
+         return \"\";
+        }
+        return (AS2 (andi,%A0,lo8(%2)) CR_TAB
+               AS2 (andi,%B0,hi8(%2)));
+     }
+  return (AS2 (ldi,%3,lo8(%2)) CR_TAB
+          AS2 (and,%A0,%3)     CR_TAB
+          AS1 (clr,%B0));
+}"
+  [(set_attr "length" "2,2,3")
+   (set_attr "cc" "set_n,clobber,clobber")])
+
+(define_insn "andsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,d")
+       (and:SI (match_operand:SI 1 "register_operand" "%0,0")
+               (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "*{
+  if (which_alternative==0)
+    return (AS2 (and, %0,%2)   CR_TAB
+           AS2 (and, %B0,%B2) CR_TAB
+           AS2 (and, %C0,%C2) CR_TAB
+           AS2 (and, %D0,%D2));
+  else if (which_alternative==1)
+    {
+      if (GET_CODE (operands[2]) == CONST_INT)
+        {
+         HOST_WIDE_INT mask = INTVAL (operands[2]);
+         if ((mask & 0xff) != 0xff)
+           output_asm_insn (AS2 (andi,%A0,lo8(%2)), operands);
+         if ((mask & 0xff00) != 0xff00)
+           output_asm_insn (AS2 (andi,%B0,hi8(%2)), operands);
+         if ((mask & 0xff0000UL) != 0xff0000UL)
+           output_asm_insn (AS2 (andi,%C0,hlo8(%2)), operands);
+         if ((mask & 0xff000000UL) != 0xff000000UL)
+           output_asm_insn (AS2 (andi,%D0,hhi8(%2)), operands);
+         return \"\";
+        }
+      return (AS2 (andi, %A0,lo8(%2))  CR_TAB
+              AS2 (andi, %B0,hi8(%2)) CR_TAB
+             AS2 (andi, %C0,hlo8(%2)) CR_TAB
+             AS2 (andi, %D0,hhi8(%2)));
+      }
+}"
+  [(set_attr "length" "4,4")
+   (set_attr "cc" "set_n,set_n")])
+
+;;|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+;; ior
+
+(define_insn "iorqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,d")
+        (ior:QI (match_operand:QI 1 "register_operand" "%0,0")
+                (match_operand:QI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "@
+       or %0,%2
+       ori %0,lo8(%2)"
+  [(set_attr "length" "1,1")
+   (set_attr "cc" "set_zn,set_zn")])
+
+(define_insn "iorhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r,d")
+       (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
+               (match_operand:HI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "*{
+  if (which_alternative==0)
+    return (AS2 (or,%A0,%A2) CR_TAB
+           AS2 (or,%B0,%B2));
+  if (GET_CODE (operands[2]) == CONST_INT)
+     {
+       int mask = INTVAL (operands[2]);
+       if (mask & 0xff)
+         output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
+       if (mask & 0xff00)
+         output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
+       return \"\";
+      }
+   return (AS2 (ori,%0,lo8(%2)) CR_TAB
+          AS2 (ori,%B0,hi8(%2)));
+}"  
+  [(set_attr "length" "2,2")
+   (set_attr "cc" "set_n,clobber")])
+
+(define_insn "*iorhi3_clobber"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (ior:HI (match_operand:HI 1 "register_operand" "%0,0")
+               (match_operand:HI 2 "immediate_operand" "M,i")))
+   (clobber (match_scratch:QI 3 "=&d,&d"))]
+  ""
+  "@
+       ldi %3,lo8(%2)\;or %A0,%3
+       ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,lo8(%2)\;or %B0,%3"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "clobber,set_n")])
+
+(define_insn "iorsi3"
+  [(set (match_operand:SI 0 "register_operand"        "=r,d")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+               (match_operand:SI 2 "nonmemory_operand" "r,i")))]
+  ""
+  "*{
+  if (which_alternative==0)
+    return (AS2 (or, %0,%2)   CR_TAB
+           AS2 (or, %B0,%B2) CR_TAB
+           AS2 (or, %C0,%C2) CR_TAB
+           AS2 (or, %D0,%D2));
+  if (GET_CODE (operands[2]) == CONST_INT)
+     {
+       HOST_WIDE_INT mask = INTVAL (operands[2]);
+       if (mask & 0xff)
+         output_asm_insn (AS2 (ori,%A0,lo8(%2)), operands);
+       if (mask & 0xff00)
+         output_asm_insn (AS2 (ori,%B0,hi8(%2)), operands);
+       if (mask & 0xff0000UL)
+         output_asm_insn (AS2 (ori,%C0,hlo8(%2)), operands);
+       if (mask & 0xff000000UL)
+         output_asm_insn (AS2 (ori,%D0,hhi8(%2)), operands);
+       return \"\";
+      }
+  return (AS2 (ori, %A0,lo8(%2))  CR_TAB
+         AS2 (ori, %B0,hi8(%2)) CR_TAB
+         AS2 (ori, %C0,hlo8(%2)) CR_TAB
+         AS2 (ori, %D0,hhi8(%2)));
+}"
+  [(set_attr "length" "4,4")
+   (set_attr "cc" "set_n,clobber")])
+
+(define_insn "*iorsi3_clobber"
+  [(set (match_operand:SI 0 "register_operand"        "=r,r")
+       (ior:SI (match_operand:SI 1 "register_operand" "%0,0")
+               (match_operand:SI 2 "immediate_operand" "M,i")))
+   (clobber (match_scratch:QI 3 "=&d,&d"))]
+  ""
+  "@
+       ldi %3,lo8(%2)\;or %A0,%3
+       ldi %3,lo8(%2)\;or %A0,%3\;ldi %3,hi8(%2)\;or %B0,%3\;ldi %3,hlo8(%2)\;or %C0,%3\;ldi %3,hhi8(%2)\;or %D0,%3"
+  [(set_attr "length" "2,8")
+   (set_attr "cc" "clobber,set_n")])
+
+;;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+;; xor
+
+(define_insn "xorqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (xor:QI (match_operand:QI 1 "register_operand" "%0")
+                (match_operand:QI 2 "register_operand" "r")))]
+  ""
+  "eor %0,%2"
+  [(set_attr "length" "1")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "xorhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+        (xor:HI (match_operand:HI 1 "register_operand" "%0")
+                (match_operand:HI 2 "register_operand" "r")))]
+  ""
+  "eor %0,%2\;eor %B0,%B2"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_n")])
+
+(define_insn "xorsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (xor:SI (match_operand:SI 1 "register_operand" "%0")
+                (match_operand:SI 2 "register_operand" "r")))]
+  ""
+  "eor %0,%2
+       eor %B0,%B2
+       eor %C0,%C2
+       eor %D0,%D2"
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_n")])
+
+;;<< << << << << << << << << << << << << << << << << << << << << << << << << <<
+;; arithmetic shift left
+
+(define_insn "ashlqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,!d,r,r")
+       (ashift:QI (match_operand:QI 1 "register_operand" "0,0,0,0")
+                  (match_operand:QI 2 "general_operand" "r,i,i,Qm")))]
+  ""
+  "* return ashlqi3_out (insn, operands, NULL);"
+  [(set_attr "length" "6,4,6,7")
+   (set_attr "cc" "clobber,set_czn,set_czn,clobber")])
+
+(define_expand "ashlhi3"
+  [(parallel [(set (match_operand:HI 0 "register_operand" "")
+                  (ashift:HI (match_operand:HI 1 "register_operand" "")
+                             (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*ashlhi3_insn"
+  [(set (match_operand:HI 0 "register_operand"           "=r,r,r,r,r,r")
+       (ashift:HI (match_operand:HI 1 "register_operand" "0,0,r,0,0,0")
+                  (match_operand:QI 2 "general_operand"  "r,P,O,K,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,X,&d,X"))]
+  ""
+  "* return ashlhi3_out (insn,operands, NULL);"
+  [(set_attr "length" "7,2,4,2,5,8")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber,clobber")])
+
+(define_expand "ashlsi3"
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+                  (ashift:SI (match_operand:SI 1 "register_operand" "")
+                             (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*ashlsi3_insn"
+  [(set (match_operand:SI 0 "register_operand"           "=r,r,r,r,r")
+       (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r,0,0")
+                  (match_operand:QI 2 "general_operand"  "r,P,O,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+  ""
+  "* return ashlsi3_out (insn,operands, NULL);"
+  [(set_attr "length" "9,4,4,7,10")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
+;; arithmetic shift right
+
+(define_expand "ashrqi3"
+  [(parallel [(set (match_operand:QI 0 "register_operand" "")
+                  (ashiftrt:QI (match_operand:QI 1 "register_operand" "")
+                               (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*ashrqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,r,r,r,r")
+       (ashiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0,0")
+                    (match_operand:QI 2 "general_operand" "r,P,K,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+  ""
+  "* return ashrqi3_out (insn,operands, NULL);"
+  [(set_attr "length" "6,1,2,4,7")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+
+(define_expand "ashrhi3"
+  [(parallel [(set (match_operand:HI 0 "register_operand" "")
+                  (ashiftrt:HI (match_operand:HI 1 "register_operand" "")
+                               (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*ashrhi3_insn"
+  [(set (match_operand:HI 0 "register_operand"             "=r,r,r,r,r,r")
+       (ashiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0")
+                    (match_operand:QI 2 "general_operand"  "r,P,K,O,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,X,&d,X"))]
+  ""
+  "* return ashrhi3_out (insn,operands, NULL);"
+  [(set_attr "length" "7,2,4,2,5,8")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber,clobber")])
+
+(define_expand "ashrsi3"
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+                  (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
+                               (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*ashrsi3_insn"
+  [(set (match_operand:SI 0 "register_operand"             "=r,r,r,r,r")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0,0")
+                    (match_operand:QI 2 "general_operand"  "r,P,O,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+  ""
+  "* return ashrsi3_out (insn,operands, NULL);"
+  [(set_attr "length" "9,4,6,7,10")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
+;; logical shift right
+
+(define_insn "lshrqi3"
+  [(set (match_operand:QI 0 "register_operand" "=r,d,r,r")
+       (lshiftrt:QI (match_operand:QI 1 "register_operand" "0,0,0,0")
+                    (match_operand:QI 2 "general_operand" "r,i,i,Qm")))]
+  ""
+  "* return lshrqi3_out (insn,operands, NULL);"
+  [(set_attr "length" "6,4,6,7")
+   (set_attr "cc" "clobber,set_czn,set_czn,clobber")])
+
+(define_expand "lshrhi3"
+  [(parallel [(set (match_operand:HI 0 "register_operand" "")
+                  (lshiftrt:HI (match_operand:HI 1 "register_operand" "")
+                               (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*lshrhi3_insn"
+  [(set (match_operand:HI 0 "register_operand"             "=r,r,r,r,r,r")
+       (lshiftrt:HI (match_operand:HI 1 "register_operand" "0,0,0,r,0,0")
+                    (match_operand:QI 2 "general_operand"  "r,P,K,O,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,X,&d,X"))]
+  ""
+  "* return lshrhi3_out (insn,operands, NULL);"
+  [(set_attr "length" "7,2,4,2,5,8")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber,clobber")])
+
+
+
+(define_expand "lshrsi3"
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+                  (lshiftrt:SI (match_operand:SI 1 "register_operand" "")
+                               (match_operand:QI 2 "general_operand" "")))
+             (clobber (match_scratch:QI 3 ""))])]
+  ""
+  "")
+
+(define_insn "*lshrsi3_insn"
+  [(set (match_operand:SI 0 "register_operand"             "=r,r,r,r,r")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r,0,0")
+                    (match_operand:QI 2 "general_operand"  "r,P,O,i,Qm")))
+   (clobber (match_scratch:QI 3 "=X,X,X,&d,X"))]
+  ""
+  "* return lshrsi3_out (insn,operands, NULL);"
+  [(set_attr "length" "9,4,4,7,10")
+   (set_attr "cc" "clobber,clobber,clobber,clobber,clobber")])
+
+;; abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x)
+;; abs
+
+(define_insn "absqi2"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (abs:QI (match_operand:QI 1 "register_operand" "0")))]
+  ""
+  "sbrc %0,7\;neg %0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "clobber")])
+
+
+(define_insn "abssf2"
+  [(set (match_operand:SF 0 "register_operand" "=d,r")
+        (abs:SF (match_operand:SF 1 "register_operand" "0,0")))]
+  ""
+  "@
+       andi %D0,0x7f
+       clt\;bld %D0,7"
+  [(set_attr "length" "1,2")
+   (set_attr "cc" "clobber,clobber")])
+
+;; 0 - x  0 - x  0 - x  0 - x  0 - x  0 - x  0 - x  0 - x  0 - x  0 - x  0 - x
+;; neg
+
+(define_insn "negqi2"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (neg:QI (match_operand:QI 1 "register_operand" "0")))]
+  ""
+  "neg %0"
+  [(set_attr "length" "1")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "neghi2"
+  [(set (match_operand:HI 0 "register_operand" "=!d,r")
+       (neg:HI (match_operand:HI 1 "register_operand" "0,0")))]
+  ""
+  "@
+       com %B0\;neg %A0\;sbci %B0,lo8(-1)
+       com %B0\;neg %A0\;sbc %B0,__zero_reg__\;inc %B0"
+  [(set_attr "length" "3,4")
+   (set_attr "cc" "set_czn,set_n")])
+
+(define_insn "negsi2"
+  [(set (match_operand:SI 0 "register_operand" "=!d,r")
+       (neg:SI (match_operand:SI 1 "register_operand" "0,0")))]
+  ""
+  "@
+       com %D0\;com %C0\;com %B0\;neg %A0\;sbci %B0,lo8(-1)\;sbci %C0,lo8(-1)\;sbci %D0,lo8(-1)
+       com %D0\;com %C0\;com %B0\;neg %A0\;brcs _PC_+8\;sec\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
+  [(set_attr "length" "7,9")
+   (set_attr "cc" "set_czn,clobber")])
+
+;; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+;; not
+
+(define_insn "one_cmplqi2"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+        (not:QI (match_operand:QI 1 "register_operand" "0")))]
+  ""
+  "com %0"
+  [(set_attr "length" "1")
+   (set_attr "cc" "set_czn")])
+
+(define_insn "one_cmplhi2"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+        (not:HI (match_operand:HI 1 "register_operand" "0")))]
+  ""
+  "com %0\;com %B0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_n")])
+
+(define_insn "one_cmplsi2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (not:SI (match_operand:SI 1 "register_operand" "0")))]
+  ""
+  "com %0\;com %B0\;com %C0\;com %D0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_n")])
+
+;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
+;; sign extend
+
+(define_insn "extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+        (sign_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
+  ""
+  "@
+       clr %B0\;sbrc %0,7\;com %B0
+       mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0"
+  [(set_attr "length" "3,4")
+   (set_attr "cc" "set_n,set_n")])
+
+(define_insn "extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+        (sign_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
+  ""
+  "@
+       clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0
+       mov %A0,%A1\;clr %B0\;sbrc %A0,7\;com %B0\;mov %C0,%B0\;mov %D0,%B0"
+  [(set_attr "length" "5,6")
+   (set_attr "cc" "clobber,clobber")])
+
+(define_insn "extendhisi2"
+  [(set (match_operand:SI 0 "register_operand"               "=r,&r")
+        (sign_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
+  ""
+  "@
+       clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0
+       mov %A0,%A1\;mov %B0,%B1\;clr %C0\;sbrc %B0,7\;com %C0\;mov %D0,%C0"
+  [(set_attr "length" "4,6")
+   (set_attr "cc" "clobber,clobber")])
+
+;; xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x xx<---x
+;; zero extend
+
+(define_insn "zero_extendqihi2"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+        (zero_extend:HI (match_operand:QI 1 "register_operand" "0,*r")))]
+  ""
+  "@
+       clr %B0
+       mov %A0,%A1\;clr %B0"
+  [(set_attr "length" "1,2")
+   (set_attr "cc" "set_n,set_n")])
+
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+        (zero_extend:SI (match_operand:QI 1 "register_operand" "0,*r")))]
+  ""
+  "@
+       clr %B0\;clr %C0\;clr %D0
+       mov %A0,%A1\;clr %B0\;clr %C0\;clr %D0"
+  [(set_attr "length" "3,4")
+   (set_attr "cc" "set_n,set_n")])
+
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=r,&r")
+        (zero_extend:SI (match_operand:HI 1 "register_operand" "0,*r")))]
+  ""
+  "@
+       clr %C0\;clr %D0
+       mov %A0,%A1\;mov %B0,%B1\;clr %C0\;clr %D0"
+  [(set_attr "length" "2,4")
+   (set_attr "cc" "set_n,set_n")])
+
+;;<=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=><=>
+;; compare
+
+(define_insn "tstqi"
+  [(set (cc0)
+        (match_operand:QI 0 "register_operand" "r"))]
+  ""
+  "tst %0"
+  [(set_attr "cc" "compare")
+   (set_attr "length" "1")])
+
+(define_insn "*negated_tstqi"
+  [(set (cc0)
+        (neg:QI (match_operand:QI 0 "register_operand" "r")))]
+  ""
+  "cp __zero_reg__,%0"
+  [(set_attr "cc" "compare")
+   (set_attr "length" "1")])
+
+(define_insn "tsthi"
+  [(set (cc0)
+        (match_operand:HI 0 "register_operand" "!w,r"))]
+  ""
+  "* return out_tsthi (insn,NULL);"
+[(set_attr "cc" "compare,compare")
+ (set_attr "length" "1,2")])
+
+(define_insn "*negated_tsthi"
+  [(set (cc0)
+        (neg:HI (match_operand:HI 0 "register_operand" "r")))]
+  ""
+  "cp __zero_reg__,%A0
+       cpc __zero_reg__,%B0"
+[(set_attr "cc" "compare")
+ (set_attr "length" "2")])
+
+(define_insn "tstsi"
+  [(set (cc0)
+        (match_operand:SI 0 "register_operand" "r"))]
+  ""
+  "* return out_tstsi (insn,NULL);"
+  [(set_attr "cc" "compare")
+   (set_attr "length" "4")])
+
+(define_insn "*negated_tstsi"
+  [(set (cc0)
+        (neg:SI (match_operand:SI 0 "register_operand" "r")))]
+  ""
+  "cp __zero_reg__,%A0
+       cpc __zero_reg__,%B0
+       cpc __zero_reg__,%C0
+       cpc __zero_reg__,%D0"
+  [(set_attr "cc" "compare")
+   (set_attr "length" "4")])
+
+
+(define_insn "cmpqi"
+  [(set (cc0)
+        (compare (match_operand:QI 0 "register_operand"  "r,d")
+                (match_operand:QI 1 "nonmemory_operand" "r,i")))]
+  ""
+  "@
+       cp %0,%1
+       cpi %0,lo8(%1)"
+  [(set_attr "cc" "compare,compare")
+   (set_attr "length" "1,1")])
+
+(define_insn "*cmpqi_sign_extend"
+  [(set (cc0)
+        (compare (sign_extend:HI
+                 (match_operand:QI 0 "register_operand"  "d"))
+                (match_operand:HI 1 "immediate_operand" "M")))]
+  ""
+  "cpi %0,lo8(%1)"
+  [(set_attr "cc" "compare")
+   (set_attr "length" "1")])
+
+(define_insn "cmphi"
+  [(set (cc0)
+       (compare (match_operand:HI 0 "register_operand"  "r,d,d,r,r")
+                (match_operand:HI 1 "nonmemory_operand" "r,M,i,M,i")))
+   (clobber (match_scratch:QI 2 "=X,X,&d,&d,&d"))]
+  ""
+  "*{
+  switch (which_alternative)
+    {
+    case 0:
+      return (AS2 (cp,%A0,%A1) CR_TAB
+              AS2 (cpc,%B0,%B1));
+    case 1:
+      if (reg_unused_after (insn, operands[0])
+          && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63
+          && TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+        return AS2 (sbiw,%0,%1);
+       else
+        return (AS2 (cpi,%0,%1) CR_TAB
+                AS2 (cpc,%B0,__zero_reg__));
+    case 2:
+      if (reg_unused_after (insn, operands[0]))
+        return (AS2 (subi,%0,lo8(%1))  CR_TAB
+                AS2 (sbci,%B0,hi8(%1)));
+      else
+        return (AS2 (ldi, %2,hi8(%1))  CR_TAB
+               AS2 (cpi, %A0,lo8(%1)) CR_TAB
+               AS2 (cpc, %B0,%2));
+   case 3:
+      return (AS2 (ldi, %2,lo8(%1))  CR_TAB
+             AS2 (cp, %A0,%2) CR_TAB
+             AS2 (cpc, %B0,__zero_reg__));
+
+   case 4:
+      return (AS2 (ldi, %2,lo8(%1))  CR_TAB
+              AS2 (cp, %A0,%2)       CR_TAB
+              AS2 (ldi, %2,hi8(%1)) CR_TAB
+             AS2 (cpc, %B0,%2));
+    }
+}" 
+  [(set_attr "cc" "compare,compare,compare,compare,compare")
+   (set_attr "length" "2,2,3,3,4")])
+
+
+(define_insn "cmpsi"
+  [(set (cc0)
+       (compare (match_operand:SI 0 "register_operand"  "r,d,d,r,r")
+                (match_operand:SI 1 "nonmemory_operand" "r,M,i,M,i")))
+   (clobber (match_scratch:QI 2 "=X,X,&d,&d,&d"))]
+  ""
+  "*{
+  switch (which_alternative)
+    {
+    case 0:
+      return (AS2 (cp,%A0,%A1) CR_TAB
+              AS2 (cpc,%B0,%B1) CR_TAB
+             AS2 (cpc,%C0,%C1) CR_TAB
+             AS2 (cpc,%D0,%D1));
+    case 1:
+      if (reg_unused_after (insn, operands[0])
+          && INTVAL (operands[1]) >= 0 && INTVAL (operands[1]) <= 63
+          && TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+        return (AS2 (sbiw,%0,%1) CR_TAB
+                AS2 (cpc,%C0,__zero_reg__) CR_TAB
+                AS2 (cpc,%D0,__zero_reg__));
+      else
+        return (AS2 (cpi,%A0,lo8(%1))  CR_TAB
+                AS2 (cpc,%B0,__zero_reg__) CR_TAB
+                AS2 (cpc,%C0,__zero_reg__) CR_TAB
+                AS2 (cpc,%D0,__zero_reg__));
+    case 2:
+      if (reg_unused_after (insn, operands[0]))
+        return (AS2 (subi,%A0,lo8(%1))  CR_TAB
+                AS2 (sbci,%B0,hi8(%1))  CR_TAB
+                AS2 (sbci,%C0,hlo8(%1))  CR_TAB
+                AS2 (sbci,%D0,hhi8(%1)));
+      else
+       return (AS2 (cpi, %A0,lo8(%1))   CR_TAB
+              AS2 (ldi, %2,hi8(%1))  CR_TAB
+              AS2 (cpc, %B0,%2)       CR_TAB
+              AS2 (ldi, %2,hlo8(%1))  CR_TAB
+              AS2 (cpc, %C0,%2)       CR_TAB
+              AS2 (ldi, %2,hhi8(%1)) CR_TAB
+              AS2 (cpc, %D0,%2));
+    case 3:
+        return (AS2 (ldi,%2,lo8(%1))        CR_TAB
+                AS2 (cp,%A0,%2)            CR_TAB
+                AS2 (cpc,%B0,__zero_reg__) CR_TAB
+                AS2 (cpc,%C0,__zero_reg__) CR_TAB
+                AS2 (cpc,%D0,__zero_reg__));
+    case 4:
+       return (AS2 (ldi, %2,lo8(%1))   CR_TAB
+               AS2 (cp, %A0,%2)        CR_TAB
+              AS2 (ldi, %2,hi8(%1))  CR_TAB
+              AS2 (cpc, %B0,%2)       CR_TAB
+              AS2 (ldi, %2,hlo8(%1))  CR_TAB
+              AS2 (cpc, %C0,%2)       CR_TAB
+              AS2 (ldi, %2,hhi8(%1)) CR_TAB
+              AS2 (cpc, %D0,%2));
+   }
+}"
+  [(set_attr "cc" "compare,compare,compare,compare,compare")
+   (set_attr "length" "4,4,7,5,8")])
+
+;; ----------------------------------------------------------------------
+;; JUMP INSTRUCTIONS
+;; ----------------------------------------------------------------------
+;; Conditional jump instructions
+
+(define_expand "beq"
+  [(set (pc)
+        (if_then_else (eq (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bne"
+  [(set (pc)
+        (if_then_else (ne (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bge"
+  [(set (pc)
+        (if_then_else (ge (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bgeu"
+  [(set (pc)
+        (if_then_else (geu (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "blt"
+  [(set (pc)
+        (if_then_else (lt (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bltu"
+  [(set (pc)
+        (if_then_else (ltu (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+
+
+/****************************************************************
+ AVR not have following conditional jumps: LE,LEU,GT,GTU.
+ Convert them all to proper jumps.
+*****************************************************************/
+
+(define_expand "ble"
+  [(set (pc)
+        (if_then_else (le (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bleu"
+  [(set (pc)
+        (if_then_else (leu (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bgt"
+  [(set (pc)
+        (if_then_else (gt (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_expand "bgtu"
+  [(set (pc)
+        (if_then_else (gtu (cc0) (const_int 0))
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  ""
+  "")
+
+(define_insn "*sbrx_branch"
+  [(set (pc)
+        (if_then_else
+        (match_operator 0 "comparison_operator"
+                        [(zero_extract
+                          (match_operand:QI 1 "register_operand" "r")
+                          (const_int 1)
+                          (match_operand 2 "immediate_operand" "n"))
+                         (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))]
+  "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)"
+  "* {
+       int comp = ((get_attr_length (insn) == 4)
+                   ? reverse_condition (GET_CODE (operands[0]))
+                   : GET_CODE (operands[0]));
+       if (comp == EQ)
+         output_asm_insn (AS2 (sbrs,%1,%2), operands);
+       else
+         output_asm_insn (AS2 (sbrc,%1,%2), operands);
+       if (get_attr_length (insn) != 4)
+         return AS1 (rjmp,%3);
+       return (AS1 (rjmp,_PC_+4) CR_TAB
+               AS1 (jmp,%3));
+     }"
+  [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3))
+                                              (const_int -2046))
+                                          (le (minus (pc) (match_dup 3))
+                                              (const_int 2046)))
+                                     (const_int 2)
+                                     (if_then_else (eq (symbol_ref "AVR_MEGA")
+                                                       (const_int 0))
+                                                   (const_int 2)
+                                                   (const_int 4))))
+   (set_attr "cc" "clobber")])
+
+(define_insn "*sbrx_and_branchsi"
+  [(set (pc)
+        (if_then_else
+        (match_operator 0 "comparison_operator"
+                        [(and:SI
+                          (match_operand:SI 1 "register_operand" "r")
+                          (match_operand:SI 2 "immediate_operand" "n"))
+                         (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))]
+  "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+   && mask_one_bit_p(INTVAL (operands[2]))"
+  "* {
+       int comp = ((get_attr_length (insn) == 4)
+                   ? reverse_condition (GET_CODE (operands[0]))
+                   : GET_CODE (operands[0]));
+       int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
+       static char buf[] = \"sbrc %A1,0\";
+       buf[3] = (comp == EQ ? 's' : 'c');
+       buf[6] = bit / 8 + 'A';
+       buf[9] = bit % 8 + '0';
+       output_asm_insn (buf, operands);
+
+       if (get_attr_length (insn) != 4)
+         return AS1 (rjmp,%3);
+       return (AS1 (rjmp,_PC_+4) CR_TAB
+               AS1 (jmp,%3));
+     }"
+  [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3))
+                                              (const_int -2046))
+                                          (le (minus (pc) (match_dup 3))
+                                              (const_int 2046)))
+                                     (const_int 2)
+                                     (if_then_else (eq (symbol_ref "AVR_MEGA")
+                                                       (const_int 0))
+                                                   (const_int 2)
+                                                   (const_int 4))))
+   (set_attr "cc" "clobber")])
+
+(define_insn "*sbrx_and_branchhi"
+  [(set (pc)
+        (if_then_else
+        (match_operator 0 "comparison_operator"
+                        [(and:HI
+                          (match_operand:HI 1 "register_operand" "r")
+                          (match_operand:HI 2 "immediate_operand" "n"))
+                         (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))]
+  "(GET_CODE (operands[0]) == EQ || GET_CODE (operands[0]) == NE)
+   && mask_one_bit_p(INTVAL (operands[2]))"
+  "* {
+       int comp = ((get_attr_length (insn) == 4)
+                   ? reverse_condition (GET_CODE (operands[0]))
+                   : GET_CODE (operands[0]));
+       int bit = mask_one_bit_p(INTVAL (operands[2])) - 1;
+       static char buf[] = \"sbrc %A1,0\";
+       buf[3] = (comp == EQ ? 's' : 'c');
+       buf[6] = bit / 8 + 'A';
+       buf[9] = bit % 8 + '0';
+       output_asm_insn (buf, operands);
+
+       if (get_attr_length (insn) != 4)
+         return AS1 (rjmp,%3);
+       return (AS1 (rjmp,_PC_+4) CR_TAB
+               AS1 (jmp,%3));
+     }"
+  [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3))
+                                              (const_int -2046))
+                                          (le (minus (pc) (match_dup 3))
+                                              (const_int 2046)))
+                                     (const_int 2)
+                                     (if_then_else (eq (symbol_ref "AVR_MEGA")
+                                                       (const_int 0))
+                                                   (const_int 2)
+                                                   (const_int 4))))
+   (set_attr "cc" "clobber")])
+
+;; ************************************************************************
+;; Implementation of conditional jumps here.
+;;  Compare with 0 (test) jumps
+;; ************************************************************************
+
+(define_insn "branch"
+  [(set (pc)
+        (if_then_else (match_operator 1 "comparison_operator"
+                        [(cc0)
+                         (const_int 0)])
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  "! (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+      || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+  "*
+   return ret_cond_branch (GET_CODE (operands[1]),
+                           avr_jump_mode (operands[0],insn));"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "clobber")])
+
+(define_insn "difficult_branch"
+  [(set (pc)
+        (if_then_else (match_operator 1 "comparison_operator"
+                        [(cc0)
+                         (const_int 0)])
+                      (label_ref (match_operand 0 "" ""))
+                      (pc)))]
+  "(GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+    || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+  "*
+   return ret_cond_branch (GET_CODE (operands[1]),
+                           avr_jump_mode (operands[0],insn));"
+  [(set_attr "type" "branch1")
+   (set_attr "cc" "clobber")])
+
+;; revers branch
+
+(define_insn "rvbranch"
+  [(set (pc)
+        (if_then_else (match_operator 1 "comparison_operator" [(cc0)
+                                                               (const_int 0)])
+                      (pc)
+                      (label_ref (match_operand 0 "" ""))))]
+  "! (GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+      || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+  "*
+   return ret_cond_branch (reverse_condition (GET_CODE (operands[1])),
+                           avr_jump_mode (operands[0],insn));"
+  [(set_attr "type" "branch1")
+   (set_attr "cc" "clobber")])
+
+(define_insn "difficult_rvbranch"
+  [(set (pc)
+        (if_then_else (match_operator 1 "comparison_operator" [(cc0)
+                                                               (const_int 0)])
+                      (pc)
+                      (label_ref (match_operand 0 "" ""))))]
+  "(GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GTU
+    || GET_CODE (operands[1]) == LE || GET_CODE (operands[1]) == LEU)"
+  "*
+   return ret_cond_branch (reverse_condition (GET_CODE (operands[1])),
+                           avr_jump_mode (operands[0],insn));"
+  [(set_attr "type" "branch")
+   (set_attr "cc" "clobber")])
+
+;; **************************************************************************
+;; Unconditional and other jump instructions.
+
+(define_insn "jump"
+  [(set (pc)
+        (label_ref (match_operand 0 "" "")))]
+  ""
+  "*{
+  if (AVR_MEGA && get_attr_length (insn) != 1)
+    return \"jmp %0\";
+  return \"rjmp %0\";
+}"
+  [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 0))
+                                              (const_int -2047))
+                                          (le (minus (pc) (match_dup 0))
+                                              (const_int 2047)))
+                                     (const_int 1)
+                                     (const_int 2)))
+   (set_attr "cc" "none")])
+
+;; call
+
+(define_expand "call"
+  [(call (match_operand:HI 0 "call_insn_operand" "")
+         (match_operand:HI 1 "general_operand" ""))]
+  ;; Operand 1 not used on the AVR.
+  ""
+  "")
+
+;; call value
+
+(define_expand "call_value"
+  [(set (match_operand 0 "register_operand" "")
+        (call (match_operand:HI 1 "call_insn_operand" "")
+              (match_operand:HI 2 "general_operand" "")))]
+  ;; Operand 2 not used on the AVR.
+  ""
+  "")
+
+(define_insn "call_insn"
+  [(call (mem:HI (match_operand:HI 0 "nonmemory_operand" "!z,*r,i"))
+         (match_operand:HI 1 "general_operand" "X,X,X"))]
+;; We don't need in saving Z register because r30,r31 is a call used registers
+  ;; Operand 1 not used on the AVR.
+  "(register_operand (operands[0], HImode) || CONSTANT_P (operands[0]))"
+  "*
+{
+  if (which_alternative==0)
+     return \"icall\";
+  else if (which_alternative==1)
+     return (AS2 (mov, r30,%A0) CR_TAB
+            AS2 (mov, r31,%B0) CR_TAB
+            \"icall\");
+  else if (!AVR_MEGA)
+     return AS1(rcall,%c0);   
+  return AS1(call,%c0);
+}"
+  [(set_attr "cc" "clobber,clobber,clobber")
+   (set (attr "length")
+       (cond [(eq (symbol_ref "which_alternative") (const_int 0))
+              (const_int 1)
+              (eq (symbol_ref "which_alternative") (const_int 0))
+              (const_int 3)
+              (eq (symbol_ref "!AVR_MEGA")
+                  (const_int 0))
+              (const_int 2)]
+       (const_int 1)))])
+
+(define_insn "call_value_insn"
+  [(set (match_operand 0 "register_operand" "=r,r,r")
+        (call (mem:HI (match_operand:HI 1 "nonmemory_operand" "!z,*r,i"))
+;; We don't need in saving Z register because r30,r31 is a call used registers
+              (match_operand:HI 2 "general_operand" "X,X,X")))]
+  ;; Operand 2 not used on the AVR.
+  "(register_operand (operands[0], VOIDmode) || CONSTANT_P (operands[0]))"
+  "*
+{
+  if (which_alternative==0)
+     return \"icall\";
+  else if (which_alternative==1)
+     return (AS2 (mov, r30,%A1) CR_TAB
+            AS2 (mov, r31,%B1) CR_TAB
+            \"icall\");
+  else if (!AVR_MEGA)
+     return AS1(rcall,%c1);   
+  return AS1(call,%c1);
+}"
+  [(set_attr "cc" "clobber,clobber,clobber")
+   (set (attr "length")
+       (cond [(eq (symbol_ref "which_alternative") (const_int 0))
+              (const_int 1)
+              (eq (symbol_ref "which_alternative") (const_int 0))
+              (const_int 3)
+              (eq (symbol_ref "!AVR_MEGA")
+                  (const_int 0))
+              (const_int 2)]
+             (const_int 1)))])
+
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop"
+  [(set_attr "cc" "none")
+   (set_attr "length" "1")])
+
+; indirect jump
+(define_insn "indirect_jump"
+  [(set (pc) (match_operand:HI 0 "register_operand" "!z,*r"))]
+  ""
+  "@
+       ijmp
+       push %A0\;push %B0\;ret"
+  [(set_attr "length" "1,3")
+   (set_attr "cc" "none,none")])
+
+;; table jump
+(define_expand "tablejump"
+  [(parallel [(set (pc) (match_operand:HI 0 "register_operand" ""))
+             (use (label_ref (match_operand 1 "" "")))])]
+  "optimize"
+  "")
+
+(define_insn "*tablejump"
+   [(set (pc) (mem:HI
+              (plus:HI (match_operand:HI 0 "register_operand" "=&z")
+                       (label_ref (match_operand 2 "" "")))))
+    (use (label_ref (match_operand 1 "" "")))]
+  ""
+  "subi r30,lo8(-(%2))
+       sbci r31,hi8(-(%2))
+       lpm
+       push r0
+        adiw r30,1
+       lpm
+       push r0
+        ret"
+  [(set_attr "length" "8")
+   (set_attr "cc" "clobber")])
+
+(define_expand "casesi"
+  [(set (match_dup 6)
+       (minus:HI (subreg:HI (match_operand:SI 0 "register_operand" "") 0)
+                 (match_operand:HI 1 "register_operand" "")))
+   (parallel [(set (cc0)
+                  (compare (match_dup 6)
+                           (match_operand:HI 2 "register_operand" "")))
+             (clobber (match_scratch:QI 9 ""))])
+   
+   (set (pc)
+       (if_then_else (gtu (cc0)
+                          (const_int 0))
+                     (label_ref (match_operand 4 "" ""))
+                     (pc)))
+   (set (match_dup 6)
+       (plus:HI (match_dup 6)
+                (match_dup 6)))
+;;   (set (match_dup 6)
+;;     (plus:HI (match_dup 6) (label_ref (match_operand:HI 3 "" ""))))
+                
+   (parallel [(set (pc) (mem:HI
+                        (plus:HI (match_dup 6)
+                                 (label_ref (match_operand:HI 3 "" "")))))
+             (use (label_ref (match_dup 3)))])]
+  "!optimize"
+  "
+{
+  operands[6] = gen_reg_rtx (HImode);
+}")
+
+
+;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+;; This instructin sets Z flag
+
+(define_insn "sez"
+  [(set (cc0) (const_int 0))]
+  ""
+  "sez"
+  [(set_attr "length" "1")
+   (set_attr "cc" "compare")])
+
+
+;; ************************* Peepholes ********************************
+
+(define_peephole
+  [(set (match_operand:SI 0 "register_operand" "")
+        (plus:SI (match_dup 0)
+                 (const_int -1)))
+   (parallel
+    [(set (cc0)
+          (compare (match_dup 0)
+                  (const_int -1)))
+     (clobber (match_operand:QI 1 "register_operand" ""))])
+   (set (pc)
+       (if_then_else (ne (cc0) (const_int 0))
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  "(true_regnum (operands[0]) >= LD_REGS
+    && true_regnum (operands[1]) >= LD_REGS)"
+  "*
+{
+  if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+    output_asm_insn (AS2 (sbiw,%0,1) CR_TAB
+                    AS2 (sbc,%C0,__zero_reg__) CR_TAB
+                    AS2 (sbc,%D0,__zero_reg__) \"\\n\", operands);
+  else
+    output_asm_insn (AS2 (subi,%A0,1) CR_TAB
+                    AS2 (sbc,%B0,__zero_reg__) CR_TAB
+                    AS2 (sbc,%C0,__zero_reg__) CR_TAB
+                    AS2 (sbc,%D0,__zero_reg__) \"\\n\", operands);
+  switch (avr_jump_mode (operands[2],insn))
+  {
+    case 1:
+      return AS1 (brcc,%2);
+    case 2:
+      return (AS1 (brcs,_PC_+2) CR_TAB
+              AS1 (rjmp,%2));
+  }
+  return (AS1 (brcs,_PC_+4) CR_TAB
+          AS1 (jmp,%2));
+}")
+
+(define_peephole
+  [(set (match_operand:HI 0 "register_operand" "")
+        (plus:HI (match_dup 0)
+                 (const_int -1)))
+   (parallel
+    [(set (cc0)
+          (compare (match_dup 0)
+                  (const_int 65535)))
+     (clobber (match_operand:QI 1 "register_operand" ""))])
+   (set (pc)
+       (if_then_else (ne (cc0) (const_int 0))
+                     (label_ref (match_operand 2 "" ""))
+                     (pc)))]
+  "(true_regnum (operands[0]) >= LD_REGS
+    && true_regnum (operands[1]) >= LD_REGS)"
+  "*
+{
+  if (TEST_HARD_REG_CLASS (ADDW_REGS, true_regnum (operands[0])))
+    output_asm_insn (AS2 (sbiw,%0,1), operands);
+  else
+    output_asm_insn (AS2 (subi,%A0,1) CR_TAB
+                    AS2 (sbc,%B0,__zero_reg__) \"\\n\", operands);
+  switch (avr_jump_mode (operands[2],insn))
+  {
+    case 1:
+      return AS1 (brcc,%2);
+    case 2:
+      return (AS1 (brcs,_PC_+2) CR_TAB
+              AS1 (rjmp,%2));
+  }
+  return (AS1 (brcs,_PC_+4) CR_TAB
+          AS1 (jmp,%2));
+}")
+
+(define_peephole
+  [(set (match_operand:QI 0 "register_operand" "")
+        (plus:QI (match_dup 0)
+                 (const_int -1)))
+   (set (cc0)
+       (compare (match_dup 0)
+                (const_int -1)))
+   (set (pc)
+       (if_then_else (ne (cc0) (const_int 0))
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))]
+  "(true_regnum (operands[0]) >= LD_REGS)"
+  "*
+{
+  output_asm_insn (AS2 (subi,%A0,1), operands);
+  switch (avr_jump_mode (operands[1],insn))
+  {
+    case 1:
+      return AS1 (brcc,%1);
+    case 2:
+      return (AS1 (brcs,_PC_+2) CR_TAB
+              AS1 (rjmp,%1));
+  }
+  return (AS1 (brcs,_PC_+4) CR_TAB
+          AS1 (jmp,%1));
+}")
+                                       
diff --git a/gcc/config/avr/libgcc.S b/gcc/config/avr/libgcc.S
new file mode 100644 (file)
index 0000000..b0e91cc
--- /dev/null
@@ -0,0 +1,666 @@
+/*  -*- Mode: Asm -*-  */
+/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Contributed by Denis Chertykov <denisc@overta.ru>
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#define TEXT_SEG(x) .section .text.libgcc ; x
+#define GLOBAL(x) .global _##x
+#define FUNCTION(x) .func _##x
+#define LABEL(x) _##x##:
+#define ENDFUNC .endfunc
+
+#define __zero_reg__ r1
+#define __tmp_reg__ r0
+#define __SREG__ 0x3f
+#define __SP_H__ 0x3e
+#define __SP_L__ 0x3d
+
+/*******************************************************
+               Multiplication  8 x 8
+*******************************************************/
+#if defined (Lmulqi3)
+
+#define        r_arg2  r25             /* multiplicand */
+#define        r_arg1  r24             /* multiplier */
+#define r_res  __tmp_reg__     /* result */
+
+TEXT_SEG(mulqi3)
+GLOBAL (mulqi3)
+FUNCTION (mulqi3)
+LABEL(mulqi3)
+
+GLOBAL (umulqi3)
+LABEL(umulqi3)
+       clr     r_res           ; clear result
+__mulqi3_loop:
+       sbrc    r_arg1,0
+       add     r_res,r_arg2
+       add     r_arg2,r_arg2   ; shift multiplicand
+       breq    __mulqi3_exit   ; while multiplicand != 0
+       lsr     r_arg1          ; 
+       brne    __mulqi3_loop   ; exit if multiplier = 0
+__mulqi3_exit: 
+       mov     r_arg1,r_res    ; result to return register
+       ret
+
+#undef r_arg2  
+#undef r_arg1  
+#undef r_res   
+       
+ENDFUNC
+#endif         /* defined (Lmulqi3) */
+
+
+/*******************************************************
+               Multiplication  16 x 16
+*******************************************************/
+#if defined (Lmulhi3)
+#define        r_arg1L r24             /* multiplier Low */
+#define        r_arg1H r25             /* multiplier High */
+#define        r_arg2L r22             /* multiplicand Low */
+#define        r_arg2H r23             /* multiplicand High */
+#define r_resL r20             /* result Low */
+#define r_resH  r21            /* result High */
+
+TEXT_SEG(mulhi3)
+GLOBAL (mulhi3)
+FUNCTION (mulhi3)
+LABEL(mulhi3)
+
+GLOBAL (umulhi3)
+LABEL(umulhi3)
+       
+       clr     r_resH          ; clear result
+       clr     r_resL          ; clear result
+__mulhi3_loop:
+       sbrs    r_arg1L,0
+       rjmp    __mulhi3_skip1
+       add     r_resL,r_arg2L  ; result + multiplicand
+       adc     r_resH,r_arg2H
+__mulhi3_skip1:        
+       add     r_arg2L,r_arg2L ; shift multiplicand
+       adc     r_arg2H,r_arg2H
+
+       cpc     r_arg2L,__zero_reg__
+       breq    __mulhi3_exit   ; while multiplicand != 0
+
+       lsr     r_arg1H         ; gets LSB of multiplier
+       ror     r_arg1L
+       cpc     r_arg1H,__zero_reg__
+       brne    __mulhi3_loop   ; exit if multiplier = 0
+__mulhi3_exit:
+       mov     r_arg1H,r_resH  ; result to return register
+       mov     r_arg1L,r_resL
+       ret
+
+#undef r_arg1L
+#undef r_arg1H
+#undef r_arg2L
+#undef r_arg2H
+#undef r_resL  
+#undef r_resH 
+
+ENDFUNC
+#endif /* defined (Lmulhi3) */
+
+#if defined (Lmulsi3)
+/*******************************************************
+               Multiplication  32 x 32
+*******************************************************/
+#define r_arg1L  r22           /* multiplier Low */
+#define r_arg1H  r23
+#define        r_arg1HL r24
+#define        r_arg1HH r25            /* multiplier High */
+
+
+#define        r_arg2L  r18            /* multiplicand Low */
+#define        r_arg2H  r19    
+#define        r_arg2HL r20
+#define        r_arg2HH r21            /* multiplicand High */
+       
+#define r_resL  r26            /* result Low */
+#define r_resH   r27
+#define r_resHL         r30
+#define r_resHH  r31           /* result High */
+
+       
+TEXT_SEG(mulsi3)
+GLOBAL (mulsi3)
+FUNCTION (mulsi3)
+LABEL(mulsi3)
+
+GLOBAL (umulsi3)
+LABEL(umulsi3)
+       clr     r_resHH         ; clear result
+       clr     r_resHL         ; clear result
+       clr     r_resH          ; clear result
+       clr     r_resL          ; clear result
+__mulsi3_loop:
+       sbrs    r_arg1L,0
+       rjmp    __mulsi3_skip1
+       add     r_resL,r_arg2L          ; result + multiplicand
+       adc     r_resH,r_arg2H
+       adc     r_resHL,r_arg2HL
+       adc     r_resHH,r_arg2HH
+__mulsi3_skip1:
+       add     r_arg2L,r_arg2L         ; shift multiplicand
+       adc     r_arg2H,r_arg2H
+       adc     r_arg2HL,r_arg2HL
+       adc     r_arg2HH,r_arg2HH
+       
+       lsr     r_arg1HH        ; gets LSB of multiplier
+       ror     r_arg1HL
+       ror     r_arg1H
+       ror     r_arg1L
+       brne    __mulsi3_loop
+       sbiw    r_arg1HL,0
+       cpc     r_arg1H,r_arg1L
+       brne    __mulsi3_loop           ; exit if multiplier = 0
+__mulsi3_exit:
+       mov     r_arg1HH,r_resHH        ; result to return register
+       mov     r_arg1HL,r_resHL
+       mov     r_arg1H,r_resH
+       mov     r_arg1L,r_resL
+       ret
+#undef r_arg1L 
+#undef r_arg1H 
+#undef r_arg1HL
+#undef r_arg1HH
+             
+             
+#undef r_arg2L 
+#undef r_arg2H 
+#undef r_arg2HL
+#undef r_arg2HH
+             
+#undef r_resL  
+#undef r_resH  
+#undef r_resHL 
+#undef r_resHH 
+
+ENDFUNC
+#endif /* defined (Lmulsi3) */
+       
+/*******************************************************
+       Division 8 / 8 => (result + remainder)
+*******************************************************/
+#define        r_rem   r26     /* remainder */
+#define        r_arg1  r25     /* dividend */
+#define        r_arg2  r24     /* divisor */
+#define        r_cnt   r27     /* loop count */
+
+#if defined (Lumodqi3)
+
+TEXT_SEG(divqi3)
+GLOBAL (umodqi3)
+FUNCTION (umodqi3)
+LABEL(umodqi3)
+       clt
+       rcall   _udivqi3
+       mov     r24,r_rem
+       ret
+ENDFUNC
+#endif /* defined (Lumodqi3) */
+       
+#if defined (Ludivqi3)
+
+TEXT_SEG(divqi3)
+GLOBAL (udivqi3)
+FUNCTION (udivqi3)
+LABEL(udivqi3)
+       clr     __tmp_reg__
+       rjmp    _divqi_raw
+ENDFUNC
+#endif /* defined (Ludivqi3) */
+
+#if defined (Lmodqi3)
+       
+TEXT_SEG (divqi3)
+GLOBAL (moqhi3)
+FUNCTION (moqhi3)
+LABEL (modqi3)
+       rcall   _divqi3
+       mov     r24,r_rem
+       ret
+ENDFUNC
+#endif /* defined (Lmodqi3) */
+
+#if defined (Ldivqi3)
+
+TEXT_SEG(divqi3)
+GLOBAL (divqi3)
+FUNCTION (divqi3)
+LABEL(divqi3)
+        bst     r_arg1,7       ; store sign of divident
+        mov     __tmp_reg__,r_arg1
+        eor     __tmp_reg__,r_arg2; r0.7 is sign of result
+        sbrc   r_arg1,7
+        neg     r_arg1         ; divident negative : negate
+        sbrc   r_arg2,7
+        neg     r_arg2         ; divisor negative : negate
+GLOBAL (divqi_raw)
+LABEL (divqi_raw)      
+       sub     r_rem,r_rem     ; clear remainder and carry
+       ldi     r_cnt,9         ; init loop counter
+       rjmp    __divqi3_ep     ; jump to entry point
+__divqi3_loop:
+        rol    r_rem           ; shift dividend into remainder
+        cp     r_rem,r_arg2    ; compare remainder & divisor
+        brcs   __divqi3_ep     ; remainder <= divisor
+        sub    r_rem,r_arg2    ; restore remainder
+__divqi3_ep:
+        rol    r_arg1          ; shift dividend (with CARRY)
+        dec    r_cnt           ; decrement loop counter
+        brne   __divqi3_loop   ; loop
+       com     r_arg1          ; complement result 
+                               ; because C flag was complemented in loop
+       brtc    __divqi3_1
+       neg     r_rem           ; correct remainder sign
+__divqi3_1:
+       sbrc    __tmp_reg__,7
+       neg     r_arg1          ; correct result sign
+__divqi3_exit:
+       mov     r24,r_arg1      ; put result to return register
+       ret
+ENDFUNC
+#endif /* defined (Ldivqi3) */
+
+#undef r_rem
+#undef r_arg1
+#undef r_arg2
+#undef r_cnt
+       
+               
+/*******************************************************
+       Division 16 / 16 => (result + remainder)
+*******************************************************/
+#define        r_remL  r26     /* remainder Low */
+#define        r_remH  r27     /* remainder High */
+       
+#define        r_arg1L r24     /* dividend Low */
+#define        r_arg1H r25     /* dividend High */
+       
+#define        r_arg2L r22     /* divisor Low */
+#define        r_arg2H r23     /* divisor High */
+       
+#define        r_cnt   r21     /* loop count */
+#if defined (Lumodhi3)
+       
+TEXT_SEG (divhi3)
+GLOBAL (umodhi3)
+FUNCTION (umodhi3)
+LABEL (umodhi3)
+       clt
+       rcall   _udivhi3
+GLOBAL (umodhi3_ret)
+LABEL (umodhi3_ret)
+       mov     r24,r_remL
+       mov     r25,r_remH
+       ret
+ENDFUNC
+#endif /* defined (Lumodhi3) */
+       
+#if defined (Ludivhi3)
+       
+TEXT_SEG (divhi3)
+GLOBAL (udivhi3)
+FUNCTION (udivhi3)
+LABEL (udivhi3)
+       clr     __tmp_reg__
+       rjmp    _divhi_raw
+ENDFUNC
+#endif /* defined (Ludivhi3) */
+
+#if defined (Lmodhi3)
+       
+TEXT_SEG (divhi3)
+GLOBAL (modhi3)
+FUNCTION (modhi3)
+LABEL (modhi3)
+GLOBAL (div)
+LABEL (div)
+       rcall   _divhi3
+       mov     r22,r24         ; needed for div () function
+       mov     r23,r25
+       rjmp    _umodhi3_ret
+ENDFUNC
+#endif /* defined (Lmodhi3) */
+       
+       
+#if defined (Ldivhi3)
+       
+TEXT_SEG (divhi3)
+GLOBAL (divhi3)
+FUNCTION (divhi3)
+LABEL (divhi3)
+        bst     r_arg1H,7      ; store sign of divident
+        mov     __tmp_reg__,r_arg1H
+        eor     __tmp_reg__,r_arg2H   ; r0.7 is sign of result
+       brtc    __divhi3_skip1
+       com     r_arg1H
+        neg     r_arg1L                ; divident negative : negate
+       sbci    r_arg1H,0xff
+__divhi3_skip1:
+        tst    r_arg2H
+       brpl    __divhi3_skip2
+       com     r_arg2H
+        neg     r_arg2L                ; divisor negative : negate
+       sbci    r_arg2H,0xff
+__divhi3_skip2:
+GLOBAL (divhi_raw)
+LABEL (divhi_raw)
+       sub     r_remL,r_remL
+       sub     r_remH,r_remH           ; clear remainder and carry
+       ldi     r_cnt,17        ; init loop counter
+       rjmp    __divhi3_ep     ; jump to entry point
+__divhi3_loop:
+        rol    r_remL          ; shift dividend into remainder
+       rol     r_remH
+        cp     r_remL,r_arg2L  ; compare remainder & divisor
+       cpc     r_remH,r_arg2H
+        brcs   __divhi3_ep     ; remainder < divisor
+        sub    r_remL,r_arg2L  ; restore remainder
+        sbc    r_remH,r_arg2H
+__divhi3_ep:
+        rol    r_arg1L         ; shift dividend (with CARRY)
+        rol    r_arg1H
+        dec    r_cnt           ; decrement loop counter
+        brne   __divhi3_loop   ; loop
+       brtc    __divhi3_1
+       com     r_remH
+       neg     r_remL          ; correct remainder sign
+       sbci    r_remH,0xff
+__divhi3_1:
+       tst     __tmp_reg__
+       brpl    __divhi3_exit
+       adiw    r_arg1L,1       ; correct result sign
+       ret
+__divhi3_exit:
+       com     r_arg1L
+       com     r_arg1H
+       ret
+ENDFUNC
+#endif /* defined (Ldivhi3) */
+       
+#undef r_remH  
+#undef r_remL  
+             
+#undef r_arg1H 
+#undef r_arg1L 
+             
+#undef r_arg2H 
+#undef r_arg2L 
+               
+#undef r_cnt           
+       
+/*******************************************************
+       Division 32 / 32 => (result + remainder)
+*******************************************************/
+#define        r_remHH r31     /* remainder High */
+#define        r_remHL r30
+#define        r_remH  r27
+#define        r_remL  r26     /* remainder Low */
+       
+#define        r_arg1HH r25    /* dividend High */
+#define        r_arg1HL r24
+#define        r_arg1H  r23
+#define        r_arg1L  r22    /* dividend Low */
+       
+#define        r_arg2HH r21    /* divisor High */
+#define        r_arg2HL r20
+#define        r_arg2H  r19
+#define        r_arg2L  r18    /* divisor Low */
+       
+#define        r_cnt   r17     /* loop count */
+
+#if defined (Lumodsi3)
+
+TEXT_SEG(divsi3)
+GLOBAL (umodsi3)
+FUNCTION (umodsi3)
+LABEL(umodsi3)
+       clt
+       rcall   _udivsi3
+GLOBAL (umodsi3_ret)
+LABEL (umodsi3_ret)
+       mov     r25,r_remHH
+       mov     r24,r_remHL
+       mov     r23,r_remH
+       mov     r22,r_remL
+GLOBAL (cleanup)
+LABEL (cleanup)
+       ret
+ENDFUNC
+#endif /* defined (Lumodsi3) */
+       
+#if defined (Ludivsi3)
+
+TEXT_SEG(divsi3)
+GLOBAL (udivsi3)
+FUNCTION (udivsi3)
+LABEL(udivsi3)
+       clr     __tmp_reg__
+       rjmp    _divsi_raw
+ENDFUNC
+#endif /* defined (Ludivsi3) */
+
+#if defined (Lmodsi3)
+       
+TEXT_SEG (divsi3)
+GLOBAL (modsi3)
+FUNCTION (modsi3)
+LABEL (modsi3)
+GLOBAL (ldiv)
+LABEL (ldiv)
+       rcall   _divsi3
+       mov     r18,r22         /* Needed for ldiv */
+       mov     r19,r23
+       mov     r20,r24
+       mov     r21,r25
+       rjmp    _umodsi3_ret
+ENDFUNC
+#endif /* defined (Lmodsi3) */
+
+#if defined (Ldivsi3)
+
+TEXT_SEG(divsi3)
+GLOBAL (divsi3)
+FUNCTION (divsi3)
+LABEL(divsi3)
+        bst     r_arg1HH,7     ; store sign of divident
+        mov     __tmp_reg__,r_arg1HH
+        eor     __tmp_reg__,r_arg2HH   ; r0.7 is sign of result
+       brtc    __divsi3_skip1
+       com     r_arg1HH
+       com     r_arg1HL
+       com     r_arg1H
+        neg     r_arg1L                ; divident negative : negate
+       sbci    r_arg1H, 0xff
+       sbci    r_arg1HL,0xff
+       sbci    r_arg1HH,0xff
+__divsi3_skip1:
+        tst    r_arg2HH
+       brpl    __divsi3_skip2
+       com     r_arg2HH
+       com     r_arg2HL
+       com     r_arg2H
+        neg     r_arg2L                ; divisor negative : negate
+       sbci    r_arg2H, 0xff
+       sbci    r_arg2HL,0xff
+       sbci    r_arg2HH,0xff
+__divsi3_skip2:
+GLOBAL (divsi_raw)
+LABEL (divsi_raw)
+       push    r_cnt
+       sub     r_remL,r_remL
+       sub     r_remH,r_remH
+       sub     r_remHL,r_remHL
+       sub     r_remHH,r_remHH ; clear remainder and carry
+       ldi     r_cnt,33        ; init loop counter
+       rjmp    __divsi3_ep     ; jump to entry point
+__divsi3_loop:
+        rol    r_remL          ; shift dividend into remainder
+       rol     r_remH
+       rol     r_remHL
+       rol     r_remHH
+        cp     r_remL,r_arg2L  ; compare remainder & divisor
+       cpc     r_remH,r_arg2H
+       cpc     r_remHL,r_arg2HL
+       cpc     r_remHH,r_arg2HH
+        brcs   __divsi3_ep     ; remainder <= divisor
+        sub    r_remL,r_arg2L  ; restore remainder
+        sbc    r_remH,r_arg2H
+        sbc    r_remHL,r_arg2HL
+        sbc    r_remHH,r_arg2HH
+__divsi3_ep:
+        rol    r_arg1L         ; shift dividend (with CARRY)
+        rol    r_arg1H
+        rol    r_arg1HL
+        rol    r_arg1HH
+        dec    r_cnt           ; decrement loop counter
+        brne   __divsi3_loop   ; loop
+       pop     r_cnt
+       brtc    __divsi3_1
+       com     r_remHH
+       com     r_remHL
+       com     r_remH
+       neg     r_remL          ; correct remainder sign
+       sbci    r_remH, 0xff
+       sbci    r_remHL,0xff
+       sbci    r_remHH,0xff
+__divsi3_1:
+       rol     __tmp_reg__
+       brcc    __divsi3_exit
+       adc     r_arg1L,__zero_reg__; correct result sign
+       adc     r_arg1H,__zero_reg__
+       adc     r_arg1HL,__zero_reg__
+       adc     r_arg1HH,__zero_reg__
+       ret
+__divsi3_exit:
+       com     r_arg1L
+       com     r_arg1H
+       com     r_arg1HL
+       com     r_arg1HH
+       ret
+ENDFUNC
+#endif /* defined (Ldivsi3) */
+
+/**********************************
+ * This is a prologue subroutine
+ **********************************/
+#if defined (Lprologue)
+
+TEXT_SEG (_prologue_saves)
+GLOBAL (_prologue_saves__)
+FUNCTION (_prologue_saves__)
+LABEL (_prologue_saves__)
+       push r2
+       push r3
+       push r4
+       push r5
+       push r6
+       push r7
+       push r8
+       push r9
+       push r10
+       push r11
+       push r12
+       push r13
+       push r14
+       push r15
+       push r16
+       push r17
+       push r28
+       push r29
+       in      r28,__SP_L__
+       in      r29,__SP_H__
+       sbiw r26,0
+       breq _prologue_end
+       sub     r28,r26
+       sbc     r29,r27
+       in      __tmp_reg__,__SREG__
+       cli
+       out     __SP_L__,r28
+       out     __SREG__,__tmp_reg__
+       out     __SP_H__,r29
+_prologue_end:
+       ijmp
+ENDFUNC
+#endif /* defined (Lprologue) */
+
+/*
+ * This is a epilogue subroutine
+ */
+#if defined (Lepilogue)
+
+TEXT_SEG (_epilogue_restores)
+GLOBAL (_epilogue_restores__)
+FUNCTION (_epilogue_restores__)
+LABEL (_epilogue_restores__)
+       ldd     r2,Y+18
+       ldd     r3,Y+17
+       ldd     r4,Y+16
+       ldd     r5,Y+15
+       ldd     r6,Y+14
+       ldd     r7,Y+13
+       ldd     r8,Y+12
+       ldd     r9,Y+11
+       ldd     r10,Y+10
+       ldd     r11,Y+9
+       ldd     r12,Y+8
+       ldd     r13,Y+7
+       ldd     r14,Y+6
+       ldd     r15,Y+5
+       ldd     r16,Y+4
+       ldd     r17,Y+3
+       ldd     r26,Y+2
+       ldd     r27,Y+1
+       add     r28,r30
+       adc     r29,__zero_reg__
+       in      __tmp_reg__,__SREG__
+       cli
+       out     __SP_L__,r28
+       out     __SREG__,__tmp_reg__
+       out     __SP_H__,r29
+       mov     r28,r26
+       mov     r29,r27
+       ret
+#endif /* defined (Lepilogue) */
+
+#ifdef L__exit
+TEXT_SEG(exit)
+GLOBAL (exit)
+FUNCTION (exit)
+LABEL(exit)
+       rjmp    _exit
+ENDFUNC
+#endif
\ No newline at end of file
diff --git a/gcc/config/avr/t-avr b/gcc/config/avr/t-avr
new file mode 100644 (file)
index 0000000..9f549f4
--- /dev/null
@@ -0,0 +1,48 @@
+# Specific names for AVR tools
+AR_FOR_TARGET = avr-ar
+RANLIB_FOR_TARGET = avr-ranlib
+
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = avr/libgcc.S
+LIB1ASMFUNCS = \
+       mulqi3 \
+       mulhi3 \
+       mulsi3 \
+       umodqi3 \
+       udivqi3 \
+       modqi3 \
+       divqi3 \
+       umodhi3 \
+       udivhi3 \
+       modhi3 \
+       divhi3 \
+       umodsi3 \
+       udivsi3 \
+       modsi3 \
+       divsi3 \
+       prologue \
+       epilogue \
+       __exit
+
+# libgcc...
+LIBGCC1_TEST =
+
+# We do not have DF type
+TARGET_LIBGCC2_CFLAGS = -DDF=SF -Dinhibit_libc
+#LIBGCC2 = $(LIBGCC1)
+
+fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/avr/t-avr
+       echo '#define FLOAT' > fp-bit.c
+       echo '#define FLOAT_ONLY' >> fp-bit.c
+       echo '#define CMPtype QItype' >> fp-bit.c
+       echo '#define DF SF' >> fp-bit.c
+       echo '#define DI SI' >> fp-bit.c
+       echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c
+       echo '#define SMALL_MACHINE' >> fp-bit.c
+       echo 'typedef int QItype __attribute__ ((mode (QI)));' >> fp-bit.c
+       cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+FPBIT = fp-bit.c
+
+
+
diff --git a/gcc/config/avr/xm-avr.h b/gcc/config/avr/xm-avr.h
new file mode 100644 (file)
index 0000000..af51cd3
--- /dev/null
@@ -0,0 +1 @@
+#include "tm.h"