OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [avr/] [avr.c] - Diff between revs 154 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Subroutines for insn-output.c for ATMEL AVR micro controllers
/* Subroutines for insn-output.c for ATMEL AVR micro controllers
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Contributed by Denis Chertykov (denisc@overta.ru)
   Contributed by Denis Chertykov (denisc@overta.ru)
 
 
   This file is part of GCC.
   This file is part of GCC.
 
 
   GCC is free software; you can redistribute it and/or modify
   GCC is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   GCC is distributed in the hope that it will be useful,
   GCC is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with GCC; see the file COPYING3.  If not see
   along with GCC; see the file COPYING3.  If not see
   <http://www.gnu.org/licenses/>.  */
   <http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "rtl.h"
#include "rtl.h"
#include "regs.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "real.h"
#include "real.h"
#include "insn-config.h"
#include "insn-config.h"
#include "conditions.h"
#include "conditions.h"
#include "insn-attr.h"
#include "insn-attr.h"
#include "flags.h"
#include "flags.h"
#include "reload.h"
#include "reload.h"
#include "tree.h"
#include "tree.h"
#include "output.h"
#include "output.h"
#include "expr.h"
#include "expr.h"
#include "toplev.h"
#include "toplev.h"
#include "obstack.h"
#include "obstack.h"
#include "function.h"
#include "function.h"
#include "recog.h"
#include "recog.h"
#include "ggc.h"
#include "ggc.h"
#include "tm_p.h"
#include "tm_p.h"
#include "target.h"
#include "target.h"
#include "target-def.h"
#include "target-def.h"
 
 
/* Maximal allowed offset for an address in the LD command */
/* Maximal allowed offset for an address in the LD command */
#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
#define MAX_LD_OFFSET(MODE) (64 - (signed)GET_MODE_SIZE (MODE))
 
 
static int avr_naked_function_p (tree);
static int avr_naked_function_p (tree);
static int interrupt_function_p (tree);
static int interrupt_function_p (tree);
static int signal_function_p (tree);
static int signal_function_p (tree);
static int avr_regs_to_save (HARD_REG_SET *);
static int avr_regs_to_save (HARD_REG_SET *);
static int sequent_regs_live (void);
static int sequent_regs_live (void);
static const char *ptrreg_to_str (int);
static const char *ptrreg_to_str (int);
static const char *cond_string (enum rtx_code);
static const char *cond_string (enum rtx_code);
static int avr_num_arg_regs (enum machine_mode, tree);
static int avr_num_arg_regs (enum machine_mode, tree);
static int out_adj_frame_ptr (FILE *, int);
static int out_adj_frame_ptr (FILE *, int);
static int out_set_stack_ptr (FILE *, int, int);
static int out_set_stack_ptr (FILE *, int, int);
static RTX_CODE compare_condition (rtx insn);
static RTX_CODE compare_condition (rtx insn);
static int compare_sign_p (rtx insn);
static int compare_sign_p (rtx insn);
static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *);
static tree avr_handle_progmem_attribute (tree *, tree, tree, int, bool *);
static tree avr_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
static tree avr_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
static tree avr_handle_fntype_attribute (tree *, tree, tree, int, bool *);
static tree avr_handle_fntype_attribute (tree *, tree, tree, int, bool *);
const struct attribute_spec avr_attribute_table[];
const struct attribute_spec avr_attribute_table[];
static bool avr_assemble_integer (rtx, unsigned int, int);
static bool avr_assemble_integer (rtx, unsigned int, int);
static void avr_file_start (void);
static void avr_file_start (void);
static void avr_file_end (void);
static void avr_file_end (void);
static void avr_output_function_prologue (FILE *, HOST_WIDE_INT);
static void avr_output_function_prologue (FILE *, HOST_WIDE_INT);
static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT);
static void avr_output_function_epilogue (FILE *, HOST_WIDE_INT);
static void avr_insert_attributes (tree, tree *);
static void avr_insert_attributes (tree, tree *);
static void avr_asm_init_sections (void);
static void avr_asm_init_sections (void);
static unsigned int avr_section_type_flags (tree, const char *, int);
static unsigned int avr_section_type_flags (tree, const char *, int);
 
 
static void avr_reorg (void);
static void avr_reorg (void);
static void avr_asm_out_ctor (rtx, int);
static void avr_asm_out_ctor (rtx, int);
static void avr_asm_out_dtor (rtx, int);
static void avr_asm_out_dtor (rtx, int);
static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
static bool avr_rtx_costs (rtx, int, int, int *);
static bool avr_rtx_costs (rtx, int, int, int *);
static int avr_address_cost (rtx);
static int avr_address_cost (rtx);
static bool avr_return_in_memory (tree, tree);
static bool avr_return_in_memory (tree, tree);
 
 
/* Allocate registers from r25 to r8 for parameters for function calls.  */
/* Allocate registers from r25 to r8 for parameters for function calls.  */
#define FIRST_CUM_REG 26
#define FIRST_CUM_REG 26
 
 
/* Temporary register RTX (gen_rtx_REG (QImode, TMP_REGNO)) */
/* Temporary register RTX (gen_rtx_REG (QImode, TMP_REGNO)) */
static GTY(()) rtx tmp_reg_rtx;
static GTY(()) rtx tmp_reg_rtx;
 
 
/* Zeroed register RTX (gen_rtx_REG (QImode, ZERO_REGNO)) */
/* Zeroed register RTX (gen_rtx_REG (QImode, ZERO_REGNO)) */
static GTY(()) rtx zero_reg_rtx;
static GTY(()) rtx zero_reg_rtx;
 
 
/* AVR register names {"r0", "r1", ..., "r31"} */
/* AVR register names {"r0", "r1", ..., "r31"} */
static const char *const avr_regnames[] = REGISTER_NAMES;
static const char *const avr_regnames[] = REGISTER_NAMES;
 
 
/* This holds the last insn address.  */
/* This holds the last insn address.  */
static int last_insn_address = 0;
static int last_insn_address = 0;
 
 
/* Commands count in the compiled file */
/* Commands count in the compiled file */
static int commands_in_file;
static int commands_in_file;
 
 
/* Commands in the functions prologues in the compiled file */
/* Commands in the functions prologues in the compiled file */
static int commands_in_prologues;
static int commands_in_prologues;
 
 
/* Commands in the functions epilogues in the compiled file */
/* Commands in the functions epilogues in the compiled file */
static int commands_in_epilogues;
static int commands_in_epilogues;
 
 
/* Prologue/Epilogue size in words */
/* Prologue/Epilogue size in words */
static int prologue_size;
static int prologue_size;
static int epilogue_size;
static int epilogue_size;
 
 
/* Size of all jump tables in the current function, in words.  */
/* Size of all jump tables in the current function, in words.  */
static int jump_tables_size;
static int jump_tables_size;
 
 
/* Preprocessor macros to define depending on MCU type.  */
/* Preprocessor macros to define depending on MCU type.  */
const char *avr_base_arch_macro;
const char *avr_base_arch_macro;
const char *avr_extra_arch_macro;
const char *avr_extra_arch_macro;
 
 
section *progmem_section;
section *progmem_section;
 
 
/* More than 8K of program memory: use "call" and "jmp".  */
/* More than 8K of program memory: use "call" and "jmp".  */
int avr_mega_p = 0;
int avr_mega_p = 0;
 
 
/* Enhanced core: use "movw", "mul", ...  */
/* Enhanced core: use "movw", "mul", ...  */
int avr_enhanced_p = 0;
int avr_enhanced_p = 0;
 
 
/* Assembler only.  */
/* Assembler only.  */
int avr_asm_only_p = 0;
int avr_asm_only_p = 0;
 
 
/* Core have 'MOVW' and 'LPM Rx,Z' instructions.  */
/* Core have 'MOVW' and 'LPM Rx,Z' instructions.  */
int avr_have_movw_lpmx_p = 0;
int avr_have_movw_lpmx_p = 0;
 
 
struct base_arch_s {
struct base_arch_s {
  int asm_only;
  int asm_only;
  int enhanced;
  int enhanced;
  int mega;
  int mega;
  int have_movw_lpmx;
  int have_movw_lpmx;
  const char *const macro;
  const char *const macro;
};
};
 
 
static const struct base_arch_s avr_arch_types[] = {
static const struct base_arch_s avr_arch_types[] = {
  { 1, 0, 0, 0,  NULL },  /* unknown device specified */
  { 1, 0, 0, 0,  NULL },  /* unknown device specified */
  { 1, 0, 0, 0, "__AVR_ARCH__=1" },
  { 1, 0, 0, 0, "__AVR_ARCH__=1" },
  { 0, 0, 0, 0, "__AVR_ARCH__=2" },
  { 0, 0, 0, 0, "__AVR_ARCH__=2" },
  { 0, 0, 0, 1, "__AVR_ARCH__=25"},
  { 0, 0, 0, 1, "__AVR_ARCH__=25"},
  { 0, 0, 1, 0, "__AVR_ARCH__=3" },
  { 0, 0, 1, 0, "__AVR_ARCH__=3" },
  { 0, 1, 0, 1, "__AVR_ARCH__=4" },
  { 0, 1, 0, 1, "__AVR_ARCH__=4" },
  { 0, 1, 1, 1, "__AVR_ARCH__=5" }
  { 0, 1, 1, 1, "__AVR_ARCH__=5" }
};
};
 
 
/* These names are used as the index into the avr_arch_types[] table
/* These names are used as the index into the avr_arch_types[] table
   above.  */
   above.  */
 
 
enum avr_arch
enum avr_arch
{
{
  ARCH_UNKNOWN,
  ARCH_UNKNOWN,
  ARCH_AVR1,
  ARCH_AVR1,
  ARCH_AVR2,
  ARCH_AVR2,
  ARCH_AVR25,
  ARCH_AVR25,
  ARCH_AVR3,
  ARCH_AVR3,
  ARCH_AVR4,
  ARCH_AVR4,
  ARCH_AVR5
  ARCH_AVR5
};
};
 
 
struct mcu_type_s {
struct mcu_type_s {
  const char *const name;
  const char *const name;
  int arch;  /* index in avr_arch_types[] */
  int arch;  /* index in avr_arch_types[] */
  /* Must lie outside user's namespace.  NULL == no macro.  */
  /* Must lie outside user's namespace.  NULL == no macro.  */
  const char *const macro;
  const char *const macro;
};
};
 
 
/* List of all known AVR MCU types - if updated, it has to be kept
/* List of all known AVR MCU types - if updated, it has to be kept
   in sync in several places (FIXME: is there a better way?):
   in sync in several places (FIXME: is there a better way?):
    - here
    - here
    - avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)
    - avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)
    - t-avr (MULTILIB_MATCHES)
    - t-avr (MULTILIB_MATCHES)
    - gas/config/tc-avr.c
    - gas/config/tc-avr.c
    - avr-libc  */
    - avr-libc  */
 
 
static const struct mcu_type_s avr_mcu_types[] = {
static const struct mcu_type_s avr_mcu_types[] = {
    /* Classic, <= 8K.  */
    /* Classic, <= 8K.  */
  { "avr2",         ARCH_AVR2, NULL },
  { "avr2",         ARCH_AVR2, NULL },
  { "at90s2313",    ARCH_AVR2, "__AVR_AT90S2313__" },
  { "at90s2313",    ARCH_AVR2, "__AVR_AT90S2313__" },
  { "at90s2323",    ARCH_AVR2, "__AVR_AT90S2323__" },
  { "at90s2323",    ARCH_AVR2, "__AVR_AT90S2323__" },
  { "at90s2333",    ARCH_AVR2, "__AVR_AT90S2333__" },
  { "at90s2333",    ARCH_AVR2, "__AVR_AT90S2333__" },
  { "at90s2343",    ARCH_AVR2, "__AVR_AT90S2343__" },
  { "at90s2343",    ARCH_AVR2, "__AVR_AT90S2343__" },
  { "attiny22",     ARCH_AVR2, "__AVR_ATtiny22__" },
  { "attiny22",     ARCH_AVR2, "__AVR_ATtiny22__" },
  { "attiny26",     ARCH_AVR2, "__AVR_ATtiny26__" },
  { "attiny26",     ARCH_AVR2, "__AVR_ATtiny26__" },
  { "at90s4414",    ARCH_AVR2, "__AVR_AT90S4414__" },
  { "at90s4414",    ARCH_AVR2, "__AVR_AT90S4414__" },
  { "at90s4433",    ARCH_AVR2, "__AVR_AT90S4433__" },
  { "at90s4433",    ARCH_AVR2, "__AVR_AT90S4433__" },
  { "at90s4434",    ARCH_AVR2, "__AVR_AT90S4434__" },
  { "at90s4434",    ARCH_AVR2, "__AVR_AT90S4434__" },
  { "at90s8515",    ARCH_AVR2, "__AVR_AT90S8515__" },
  { "at90s8515",    ARCH_AVR2, "__AVR_AT90S8515__" },
  { "at90c8534",    ARCH_AVR2, "__AVR_AT90C8534__" },
  { "at90c8534",    ARCH_AVR2, "__AVR_AT90C8534__" },
  { "at90s8535",    ARCH_AVR2, "__AVR_AT90S8535__" },
  { "at90s8535",    ARCH_AVR2, "__AVR_AT90S8535__" },
    /* Classic + MOVW, <= 8K.  */
    /* Classic + MOVW, <= 8K.  */
  { "avr25",        ARCH_AVR25, NULL },
  { "avr25",        ARCH_AVR25, NULL },
  { "attiny13",     ARCH_AVR25, "__AVR_ATtiny13__" },
  { "attiny13",     ARCH_AVR25, "__AVR_ATtiny13__" },
  { "attiny2313",   ARCH_AVR25, "__AVR_ATtiny2313__" },
  { "attiny2313",   ARCH_AVR25, "__AVR_ATtiny2313__" },
  { "attiny24",     ARCH_AVR25, "__AVR_ATtiny24__" },
  { "attiny24",     ARCH_AVR25, "__AVR_ATtiny24__" },
  { "attiny44",     ARCH_AVR25, "__AVR_ATtiny44__" },
  { "attiny44",     ARCH_AVR25, "__AVR_ATtiny44__" },
  { "attiny84",     ARCH_AVR25, "__AVR_ATtiny84__" },
  { "attiny84",     ARCH_AVR25, "__AVR_ATtiny84__" },
  { "attiny25",     ARCH_AVR25, "__AVR_ATtiny25__" },
  { "attiny25",     ARCH_AVR25, "__AVR_ATtiny25__" },
  { "attiny45",     ARCH_AVR25, "__AVR_ATtiny45__" },
  { "attiny45",     ARCH_AVR25, "__AVR_ATtiny45__" },
  { "attiny85",     ARCH_AVR25, "__AVR_ATtiny85__" },
  { "attiny85",     ARCH_AVR25, "__AVR_ATtiny85__" },
  { "attiny261",    ARCH_AVR25, "__AVR_ATtiny261__" },
  { "attiny261",    ARCH_AVR25, "__AVR_ATtiny261__" },
  { "attiny461",    ARCH_AVR25, "__AVR_ATtiny461__" },
  { "attiny461",    ARCH_AVR25, "__AVR_ATtiny461__" },
  { "attiny861",    ARCH_AVR25, "__AVR_ATtiny861__" },
  { "attiny861",    ARCH_AVR25, "__AVR_ATtiny861__" },
  { "at86rf401",    ARCH_AVR25, "__AVR_AT86RF401__" },
  { "at86rf401",    ARCH_AVR25, "__AVR_AT86RF401__" },
    /* Classic, > 8K.  */
    /* Classic, > 8K.  */
  { "avr3",         ARCH_AVR3, NULL },
  { "avr3",         ARCH_AVR3, NULL },
  { "atmega103",    ARCH_AVR3, "__AVR_ATmega103__" },
  { "atmega103",    ARCH_AVR3, "__AVR_ATmega103__" },
  { "atmega603",    ARCH_AVR3, "__AVR_ATmega603__" },
  { "atmega603",    ARCH_AVR3, "__AVR_ATmega603__" },
  { "at43usb320",   ARCH_AVR3, "__AVR_AT43USB320__" },
  { "at43usb320",   ARCH_AVR3, "__AVR_AT43USB320__" },
  { "at43usb355",   ARCH_AVR3, "__AVR_AT43USB355__" },
  { "at43usb355",   ARCH_AVR3, "__AVR_AT43USB355__" },
  { "at76c711",     ARCH_AVR3, "__AVR_AT76C711__" },
  { "at76c711",     ARCH_AVR3, "__AVR_AT76C711__" },
    /* Enhanced, <= 8K.  */
    /* Enhanced, <= 8K.  */
  { "avr4",         ARCH_AVR4, NULL },
  { "avr4",         ARCH_AVR4, NULL },
  { "atmega8",      ARCH_AVR4, "__AVR_ATmega8__" },
  { "atmega8",      ARCH_AVR4, "__AVR_ATmega8__" },
  { "atmega48",     ARCH_AVR4, "__AVR_ATmega48__" },
  { "atmega48",     ARCH_AVR4, "__AVR_ATmega48__" },
  { "atmega88",     ARCH_AVR4, "__AVR_ATmega88__" },
  { "atmega88",     ARCH_AVR4, "__AVR_ATmega88__" },
  { "atmega8515",   ARCH_AVR4, "__AVR_ATmega8515__" },
  { "atmega8515",   ARCH_AVR4, "__AVR_ATmega8515__" },
  { "atmega8535",   ARCH_AVR4, "__AVR_ATmega8535__" },
  { "atmega8535",   ARCH_AVR4, "__AVR_ATmega8535__" },
  { "atmega8hva",   ARCH_AVR4, "__AVR_ATmega8HVA__" },
  { "atmega8hva",   ARCH_AVR4, "__AVR_ATmega8HVA__" },
  { "at90pwm1",     ARCH_AVR4, "__AVR_AT90PWM1__" },
  { "at90pwm1",     ARCH_AVR4, "__AVR_AT90PWM1__" },
  { "at90pwm2",     ARCH_AVR4, "__AVR_AT90PWM2__" },
  { "at90pwm2",     ARCH_AVR4, "__AVR_AT90PWM2__" },
  { "at90pwm3",     ARCH_AVR4, "__AVR_AT90PWM3__" },
  { "at90pwm3",     ARCH_AVR4, "__AVR_AT90PWM3__" },
    /* Enhanced, > 8K.  */
    /* Enhanced, > 8K.  */
  { "avr5",         ARCH_AVR5, NULL },
  { "avr5",         ARCH_AVR5, NULL },
  { "atmega16",     ARCH_AVR5, "__AVR_ATmega16__" },
  { "atmega16",     ARCH_AVR5, "__AVR_ATmega16__" },
  { "atmega161",    ARCH_AVR5, "__AVR_ATmega161__" },
  { "atmega161",    ARCH_AVR5, "__AVR_ATmega161__" },
  { "atmega162",    ARCH_AVR5, "__AVR_ATmega162__" },
  { "atmega162",    ARCH_AVR5, "__AVR_ATmega162__" },
  { "atmega163",    ARCH_AVR5, "__AVR_ATmega163__" },
  { "atmega163",    ARCH_AVR5, "__AVR_ATmega163__" },
  { "atmega164p",   ARCH_AVR5, "__AVR_ATmega164P__" },
  { "atmega164p",   ARCH_AVR5, "__AVR_ATmega164P__" },
  { "atmega165",    ARCH_AVR5, "__AVR_ATmega165__" },
  { "atmega165",    ARCH_AVR5, "__AVR_ATmega165__" },
  { "atmega165p",   ARCH_AVR5, "__AVR_ATmega165P__" },
  { "atmega165p",   ARCH_AVR5, "__AVR_ATmega165P__" },
  { "atmega168",    ARCH_AVR5, "__AVR_ATmega168__" },
  { "atmega168",    ARCH_AVR5, "__AVR_ATmega168__" },
  { "atmega169",    ARCH_AVR5, "__AVR_ATmega169__" },
  { "atmega169",    ARCH_AVR5, "__AVR_ATmega169__" },
  { "atmega169p",   ARCH_AVR5, "__AVR_ATmega169P__" },
  { "atmega169p",   ARCH_AVR5, "__AVR_ATmega169P__" },
  { "atmega32",     ARCH_AVR5, "__AVR_ATmega32__" },
  { "atmega32",     ARCH_AVR5, "__AVR_ATmega32__" },
  { "atmega323",    ARCH_AVR5, "__AVR_ATmega323__" },
  { "atmega323",    ARCH_AVR5, "__AVR_ATmega323__" },
  { "atmega324p",   ARCH_AVR5, "__AVR_ATmega324P__" },
  { "atmega324p",   ARCH_AVR5, "__AVR_ATmega324P__" },
  { "atmega325",    ARCH_AVR5, "__AVR_ATmega325__" },
  { "atmega325",    ARCH_AVR5, "__AVR_ATmega325__" },
  { "atmega325p",   ARCH_AVR5, "__AVR_ATmega325P__" },
  { "atmega325p",   ARCH_AVR5, "__AVR_ATmega325P__" },
  { "atmega3250",   ARCH_AVR5, "__AVR_ATmega3250__" },
  { "atmega3250",   ARCH_AVR5, "__AVR_ATmega3250__" },
  { "atmega3250p",  ARCH_AVR5, "__AVR_ATmega3250P__" },
  { "atmega3250p",  ARCH_AVR5, "__AVR_ATmega3250P__" },
  { "atmega329",    ARCH_AVR5, "__AVR_ATmega329__" },
  { "atmega329",    ARCH_AVR5, "__AVR_ATmega329__" },
  { "atmega329p",   ARCH_AVR5, "__AVR_ATmega329P__" },
  { "atmega329p",   ARCH_AVR5, "__AVR_ATmega329P__" },
  { "atmega3290",   ARCH_AVR5, "__AVR_ATmega3290__" },
  { "atmega3290",   ARCH_AVR5, "__AVR_ATmega3290__" },
  { "atmega3290p",  ARCH_AVR5, "__AVR_ATmega3290P__" },
  { "atmega3290p",  ARCH_AVR5, "__AVR_ATmega3290P__" },
  { "atmega406",    ARCH_AVR5, "__AVR_ATmega406__" },
  { "atmega406",    ARCH_AVR5, "__AVR_ATmega406__" },
  { "atmega64",     ARCH_AVR5, "__AVR_ATmega64__" },
  { "atmega64",     ARCH_AVR5, "__AVR_ATmega64__" },
  { "atmega640",    ARCH_AVR5, "__AVR_ATmega640__" },
  { "atmega640",    ARCH_AVR5, "__AVR_ATmega640__" },
  { "atmega644",    ARCH_AVR5, "__AVR_ATmega644__" },
  { "atmega644",    ARCH_AVR5, "__AVR_ATmega644__" },
  { "atmega644p",   ARCH_AVR5, "__AVR_ATmega644P__" },
  { "atmega644p",   ARCH_AVR5, "__AVR_ATmega644P__" },
  { "atmega645",    ARCH_AVR5, "__AVR_ATmega645__" },
  { "atmega645",    ARCH_AVR5, "__AVR_ATmega645__" },
  { "atmega6450",   ARCH_AVR5, "__AVR_ATmega6450__" },
  { "atmega6450",   ARCH_AVR5, "__AVR_ATmega6450__" },
  { "atmega649",    ARCH_AVR5, "__AVR_ATmega649__" },
  { "atmega649",    ARCH_AVR5, "__AVR_ATmega649__" },
  { "atmega6490",   ARCH_AVR5, "__AVR_ATmega6490__" },
  { "atmega6490",   ARCH_AVR5, "__AVR_ATmega6490__" },
  { "atmega128",    ARCH_AVR5, "__AVR_ATmega128__" },
  { "atmega128",    ARCH_AVR5, "__AVR_ATmega128__" },
  { "atmega1280",   ARCH_AVR5, "__AVR_ATmega1280__" },
  { "atmega1280",   ARCH_AVR5, "__AVR_ATmega1280__" },
  { "atmega1281",   ARCH_AVR5, "__AVR_ATmega1281__" },
  { "atmega1281",   ARCH_AVR5, "__AVR_ATmega1281__" },
  { "atmega16hva",  ARCH_AVR5, "__AVR_ATmega16HVA__" },
  { "atmega16hva",  ARCH_AVR5, "__AVR_ATmega16HVA__" },
  { "at90can32",    ARCH_AVR5, "__AVR_AT90CAN32__" },
  { "at90can32",    ARCH_AVR5, "__AVR_AT90CAN32__" },
  { "at90can64",    ARCH_AVR5, "__AVR_AT90CAN64__" },
  { "at90can64",    ARCH_AVR5, "__AVR_AT90CAN64__" },
  { "at90can128",   ARCH_AVR5, "__AVR_AT90CAN128__" },
  { "at90can128",   ARCH_AVR5, "__AVR_AT90CAN128__" },
  { "at90usb82",    ARCH_AVR5, "__AVR_AT90USB82__" },
  { "at90usb82",    ARCH_AVR5, "__AVR_AT90USB82__" },
  { "at90usb162",   ARCH_AVR5, "__AVR_AT90USB162__" },
  { "at90usb162",   ARCH_AVR5, "__AVR_AT90USB162__" },
  { "at90usb646",   ARCH_AVR5, "__AVR_AT90USB646__" },
  { "at90usb646",   ARCH_AVR5, "__AVR_AT90USB646__" },
  { "at90usb647",   ARCH_AVR5, "__AVR_AT90USB647__" },
  { "at90usb647",   ARCH_AVR5, "__AVR_AT90USB647__" },
  { "at90usb1286",  ARCH_AVR5, "__AVR_AT90USB1286__" },
  { "at90usb1286",  ARCH_AVR5, "__AVR_AT90USB1286__" },
  { "at90usb1287",  ARCH_AVR5, "__AVR_AT90USB1287__" },
  { "at90usb1287",  ARCH_AVR5, "__AVR_AT90USB1287__" },
  { "at94k",        ARCH_AVR5, "__AVR_AT94K__" },
  { "at94k",        ARCH_AVR5, "__AVR_AT94K__" },
    /* Assembler only.  */
    /* Assembler only.  */
  { "avr1",         ARCH_AVR1, NULL },
  { "avr1",         ARCH_AVR1, NULL },
  { "at90s1200",    ARCH_AVR1, "__AVR_AT90S1200__" },
  { "at90s1200",    ARCH_AVR1, "__AVR_AT90S1200__" },
  { "attiny11",     ARCH_AVR1, "__AVR_ATtiny11__" },
  { "attiny11",     ARCH_AVR1, "__AVR_ATtiny11__" },
  { "attiny12",     ARCH_AVR1, "__AVR_ATtiny12__" },
  { "attiny12",     ARCH_AVR1, "__AVR_ATtiny12__" },
  { "attiny15",     ARCH_AVR1, "__AVR_ATtiny15__" },
  { "attiny15",     ARCH_AVR1, "__AVR_ATtiny15__" },
  { "attiny28",     ARCH_AVR1, "__AVR_ATtiny28__" },
  { "attiny28",     ARCH_AVR1, "__AVR_ATtiny28__" },
  { NULL,           ARCH_UNKNOWN, NULL }
  { NULL,           ARCH_UNKNOWN, NULL }
};
};
 
 
int avr_case_values_threshold = 30000;
int avr_case_values_threshold = 30000;


/* Initialize the GCC target structure.  */
/* Initialize the GCC target structure.  */
#undef TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
#undef TARGET_ASM_ALIGNED_SI_OP
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.long\t"
#define TARGET_ASM_ALIGNED_SI_OP "\t.long\t"
#undef TARGET_ASM_UNALIGNED_HI_OP
#undef TARGET_ASM_UNALIGNED_HI_OP
#define TARGET_ASM_UNALIGNED_HI_OP "\t.word\t"
#define TARGET_ASM_UNALIGNED_HI_OP "\t.word\t"
#undef TARGET_ASM_UNALIGNED_SI_OP
#undef TARGET_ASM_UNALIGNED_SI_OP
#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
#undef TARGET_ASM_INTEGER
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER avr_assemble_integer
#define TARGET_ASM_INTEGER avr_assemble_integer
#undef TARGET_ASM_FILE_START
#undef TARGET_ASM_FILE_START
#define TARGET_ASM_FILE_START avr_file_start
#define TARGET_ASM_FILE_START avr_file_start
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
#undef TARGET_ASM_FILE_END
#undef TARGET_ASM_FILE_END
#define TARGET_ASM_FILE_END avr_file_end
#define TARGET_ASM_FILE_END avr_file_end
 
 
#undef TARGET_ASM_FUNCTION_PROLOGUE
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
#define TARGET_ASM_FUNCTION_PROLOGUE avr_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
#define TARGET_ASM_FUNCTION_EPILOGUE avr_output_function_epilogue
#undef TARGET_ATTRIBUTE_TABLE
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE avr_attribute_table
#define TARGET_ATTRIBUTE_TABLE avr_attribute_table
#undef TARGET_ASM_FUNCTION_RODATA_SECTION
#undef TARGET_ASM_FUNCTION_RODATA_SECTION
#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
#define TARGET_ASM_FUNCTION_RODATA_SECTION default_no_function_rodata_section
#undef TARGET_INSERT_ATTRIBUTES
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES avr_insert_attributes
#define TARGET_INSERT_ATTRIBUTES avr_insert_attributes
#undef TARGET_SECTION_TYPE_FLAGS
#undef TARGET_SECTION_TYPE_FLAGS
#define TARGET_SECTION_TYPE_FLAGS avr_section_type_flags
#define TARGET_SECTION_TYPE_FLAGS avr_section_type_flags
#undef TARGET_RTX_COSTS
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS avr_rtx_costs
#define TARGET_RTX_COSTS avr_rtx_costs
#undef TARGET_ADDRESS_COST
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST avr_address_cost
#define TARGET_ADDRESS_COST avr_address_cost
#undef TARGET_MACHINE_DEPENDENT_REORG
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG avr_reorg
#define TARGET_MACHINE_DEPENDENT_REORG avr_reorg
 
 
#undef TARGET_RETURN_IN_MEMORY
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY avr_return_in_memory
#define TARGET_RETURN_IN_MEMORY avr_return_in_memory
 
 
#undef TARGET_STRICT_ARGUMENT_NAMING
#undef TARGET_STRICT_ARGUMENT_NAMING
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
 
 
struct gcc_target targetm = TARGET_INITIALIZER;
struct gcc_target targetm = TARGET_INITIALIZER;


void
void
avr_override_options (void)
avr_override_options (void)
{
{
  const struct mcu_type_s *t;
  const struct mcu_type_s *t;
  const struct base_arch_s *base;
  const struct base_arch_s *base;
 
 
  flag_delete_null_pointer_checks = 0;
  flag_delete_null_pointer_checks = 0;
 
 
  for (t = avr_mcu_types; t->name; t++)
  for (t = avr_mcu_types; t->name; t++)
    if (strcmp (t->name, avr_mcu_name) == 0)
    if (strcmp (t->name, avr_mcu_name) == 0)
      break;
      break;
 
 
  if (!t->name)
  if (!t->name)
    {
    {
      fprintf (stderr, "unknown MCU '%s' specified\nKnown MCU names:\n",
      fprintf (stderr, "unknown MCU '%s' specified\nKnown MCU names:\n",
               avr_mcu_name);
               avr_mcu_name);
      for (t = avr_mcu_types; t->name; t++)
      for (t = avr_mcu_types; t->name; t++)
        fprintf (stderr,"   %s\n", t->name);
        fprintf (stderr,"   %s\n", t->name);
    }
    }
 
 
  base = &avr_arch_types[t->arch];
  base = &avr_arch_types[t->arch];
  avr_asm_only_p = base->asm_only;
  avr_asm_only_p = base->asm_only;
  avr_enhanced_p = base->enhanced;
  avr_enhanced_p = base->enhanced;
  avr_mega_p = base->mega;
  avr_mega_p = base->mega;
  avr_have_movw_lpmx_p = base->have_movw_lpmx;
  avr_have_movw_lpmx_p = base->have_movw_lpmx;
  avr_base_arch_macro = base->macro;
  avr_base_arch_macro = base->macro;
  avr_extra_arch_macro = t->macro;
  avr_extra_arch_macro = t->macro;
 
 
  if (optimize && !TARGET_NO_TABLEJUMP)
  if (optimize && !TARGET_NO_TABLEJUMP)
    avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
    avr_case_values_threshold = (!AVR_MEGA || TARGET_CALL_PROLOGUES) ? 8 : 17;
 
 
  tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
  tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
  zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
  zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
}
}
 
 
/*  return register class from register number.  */
/*  return register class from register number.  */
 
 
static const int reg_class_tab[]={
static const 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,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 */
  GENERAL_REGS, /* r0 - r15 */
  LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,
  LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,LD_REGS,
  LD_REGS,                      /* r16 - 23 */
  LD_REGS,                      /* r16 - 23 */
  ADDW_REGS,ADDW_REGS,          /* r24,r25 */
  ADDW_REGS,ADDW_REGS,          /* r24,r25 */
  POINTER_X_REGS,POINTER_X_REGS, /* r26,27 */
  POINTER_X_REGS,POINTER_X_REGS, /* r26,27 */
  POINTER_Y_REGS,POINTER_Y_REGS, /* r28,r29 */
  POINTER_Y_REGS,POINTER_Y_REGS, /* r28,r29 */
  POINTER_Z_REGS,POINTER_Z_REGS, /* r30,r31 */
  POINTER_Z_REGS,POINTER_Z_REGS, /* r30,r31 */
  STACK_REG,STACK_REG           /* SPL,SPH */
  STACK_REG,STACK_REG           /* SPL,SPH */
};
};
 
 
/* Return register class for register R.  */
/* Return register class for register R.  */
 
 
enum reg_class
enum reg_class
avr_regno_reg_class (int r)
avr_regno_reg_class (int r)
{
{
  if (r <= 33)
  if (r <= 33)
    return reg_class_tab[r];
    return reg_class_tab[r];
  return ALL_REGS;
  return ALL_REGS;
}
}
 
 
/* Return nonzero if FUNC is a naked function.  */
/* Return nonzero if FUNC is a naked function.  */
 
 
static int
static int
avr_naked_function_p (tree func)
avr_naked_function_p (tree func)
{
{
  tree a;
  tree a;
 
 
  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
  gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
 
 
  a = lookup_attribute ("naked", TYPE_ATTRIBUTES (TREE_TYPE (func)));
  a = lookup_attribute ("naked", TYPE_ATTRIBUTES (TREE_TYPE (func)));
  return a != NULL_TREE;
  return a != NULL_TREE;
}
}
 
 
/* Return nonzero if FUNC is an interrupt function as specified
/* Return nonzero if FUNC is an interrupt function as specified
   by the "interrupt" attribute.  */
   by the "interrupt" attribute.  */
 
 
static int
static int
interrupt_function_p (tree func)
interrupt_function_p (tree func)
{
{
  tree a;
  tree a;
 
 
  if (TREE_CODE (func) != FUNCTION_DECL)
  if (TREE_CODE (func) != FUNCTION_DECL)
    return 0;
    return 0;
 
 
  a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
  a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
  return a != NULL_TREE;
  return a != NULL_TREE;
}
}
 
 
/* Return nonzero if FUNC is a signal function as specified
/* Return nonzero if FUNC is a signal function as specified
   by the "signal" attribute.  */
   by the "signal" attribute.  */
 
 
static int
static int
signal_function_p (tree func)
signal_function_p (tree func)
{
{
  tree a;
  tree a;
 
 
  if (TREE_CODE (func) != FUNCTION_DECL)
  if (TREE_CODE (func) != FUNCTION_DECL)
    return 0;
    return 0;
 
 
  a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
  a = lookup_attribute ("signal", DECL_ATTRIBUTES (func));
  return a != NULL_TREE;
  return a != NULL_TREE;
}
}
 
 
/* Return the number of hard registers to push/pop in the prologue/epilogue
/* Return the number of hard registers to push/pop in the prologue/epilogue
   of the current function, and optionally store these registers in SET.  */
   of the current function, and optionally store these registers in SET.  */
 
 
static int
static int
avr_regs_to_save (HARD_REG_SET *set)
avr_regs_to_save (HARD_REG_SET *set)
{
{
  int reg, count;
  int reg, count;
  int int_or_sig_p = (interrupt_function_p (current_function_decl)
  int int_or_sig_p = (interrupt_function_p (current_function_decl)
                      || signal_function_p (current_function_decl));
                      || signal_function_p (current_function_decl));
  int leaf_func_p = leaf_function_p ();
  int leaf_func_p = leaf_function_p ();
 
 
  if (set)
  if (set)
    CLEAR_HARD_REG_SET (*set);
    CLEAR_HARD_REG_SET (*set);
  count = 0;
  count = 0;
 
 
  /* No need to save any registers if the function never returns.  */
  /* No need to save any registers if the function never returns.  */
  if (TREE_THIS_VOLATILE (current_function_decl))
  if (TREE_THIS_VOLATILE (current_function_decl))
    return 0;
    return 0;
 
 
  for (reg = 0; reg < 32; reg++)
  for (reg = 0; reg < 32; reg++)
    {
    {
      /* Do not push/pop __tmp_reg__, __zero_reg__, as well as
      /* Do not push/pop __tmp_reg__, __zero_reg__, as well as
         any global register variables.  */
         any global register variables.  */
      if (fixed_regs[reg])
      if (fixed_regs[reg])
        continue;
        continue;
 
 
      if ((int_or_sig_p && !leaf_func_p && call_used_regs[reg])
      if ((int_or_sig_p && !leaf_func_p && call_used_regs[reg])
          || (regs_ever_live[reg]
          || (regs_ever_live[reg]
              && (int_or_sig_p || !call_used_regs[reg])
              && (int_or_sig_p || !call_used_regs[reg])
              && !(frame_pointer_needed
              && !(frame_pointer_needed
                   && (reg == REG_Y || reg == (REG_Y+1)))))
                   && (reg == REG_Y || reg == (REG_Y+1)))))
        {
        {
          if (set)
          if (set)
            SET_HARD_REG_BIT (*set, reg);
            SET_HARD_REG_BIT (*set, reg);
          count++;
          count++;
        }
        }
    }
    }
  return count;
  return count;
}
}
 
 
/* Compute offset between arg_pointer and frame_pointer.  */
/* Compute offset between arg_pointer and frame_pointer.  */
 
 
int
int
initial_elimination_offset (int from, int to)
initial_elimination_offset (int from, int to)
{
{
  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
    return 0;
    return 0;
  else
  else
    {
    {
      int offset = frame_pointer_needed ? 2 : 0;
      int offset = frame_pointer_needed ? 2 : 0;
 
 
      offset += avr_regs_to_save (NULL);
      offset += avr_regs_to_save (NULL);
      return get_frame_size () + 2 + 1 + offset;
      return get_frame_size () + 2 + 1 + offset;
    }
    }
}
}
 
 
/* Return 1 if the function epilogue is just a single "ret".  */
/* Return 1 if the function epilogue is just a single "ret".  */
 
 
int
int
avr_simple_epilogue (void)
avr_simple_epilogue (void)
{
{
  return (! frame_pointer_needed
  return (! frame_pointer_needed
          && get_frame_size () == 0
          && get_frame_size () == 0
          && avr_regs_to_save (NULL) == 0
          && avr_regs_to_save (NULL) == 0
          && ! interrupt_function_p (current_function_decl)
          && ! interrupt_function_p (current_function_decl)
          && ! signal_function_p (current_function_decl)
          && ! signal_function_p (current_function_decl)
          && ! avr_naked_function_p (current_function_decl)
          && ! avr_naked_function_p (current_function_decl)
          && ! MAIN_NAME_P (DECL_NAME (current_function_decl))
          && ! MAIN_NAME_P (DECL_NAME (current_function_decl))
          && ! TREE_THIS_VOLATILE (current_function_decl));
          && ! TREE_THIS_VOLATILE (current_function_decl));
}
}
 
 
/* This function checks sequence of live registers.  */
/* This function checks sequence of live registers.  */
 
 
static int
static int
sequent_regs_live (void)
sequent_regs_live (void)
{
{
  int reg;
  int reg;
  int live_seq=0;
  int live_seq=0;
  int cur_seq=0;
  int cur_seq=0;
 
 
  for (reg = 0; reg < 18; ++reg)
  for (reg = 0; reg < 18; ++reg)
    {
    {
      if (!call_used_regs[reg])
      if (!call_used_regs[reg])
        {
        {
          if (regs_ever_live[reg])
          if (regs_ever_live[reg])
            {
            {
              ++live_seq;
              ++live_seq;
              ++cur_seq;
              ++cur_seq;
            }
            }
          else
          else
            cur_seq = 0;
            cur_seq = 0;
        }
        }
    }
    }
 
 
  if (!frame_pointer_needed)
  if (!frame_pointer_needed)
    {
    {
      if (regs_ever_live[REG_Y])
      if (regs_ever_live[REG_Y])
        {
        {
          ++live_seq;
          ++live_seq;
          ++cur_seq;
          ++cur_seq;
        }
        }
      else
      else
        cur_seq = 0;
        cur_seq = 0;
 
 
      if (regs_ever_live[REG_Y+1])
      if (regs_ever_live[REG_Y+1])
        {
        {
          ++live_seq;
          ++live_seq;
          ++cur_seq;
          ++cur_seq;
        }
        }
      else
      else
        cur_seq = 0;
        cur_seq = 0;
    }
    }
  else
  else
    {
    {
      cur_seq += 2;
      cur_seq += 2;
      live_seq += 2;
      live_seq += 2;
    }
    }
  return (cur_seq == live_seq) ? live_seq : 0;
  return (cur_seq == live_seq) ? live_seq : 0;
}
}
 
 
 
 
/* Output to FILE the asm instructions to adjust the frame pointer by
/* Output to FILE the asm instructions to adjust the frame pointer by
   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
   ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative
   (epilogue).  Returns the number of instructions generated.  */
   (epilogue).  Returns the number of instructions generated.  */
 
 
static int
static int
out_adj_frame_ptr (FILE *file, int adj)
out_adj_frame_ptr (FILE *file, int adj)
{
{
  int size = 0;
  int size = 0;
 
 
  if (adj)
  if (adj)
    {
    {
      if (TARGET_TINY_STACK)
      if (TARGET_TINY_STACK)
        {
        {
          if (adj < -63 || adj > 63)
          if (adj < -63 || adj > 63)
            warning (0, "large frame pointer change (%d) with -mtiny-stack", adj);
            warning (0, "large frame pointer change (%d) with -mtiny-stack", adj);
 
 
          /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
          /* The high byte (r29) doesn't change - prefer "subi" (1 cycle)
             over "sbiw" (2 cycles, same size).  */
             over "sbiw" (2 cycles, same size).  */
 
 
          fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);
          fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj);
          size++;
          size++;
        }
        }
      else if (adj < -63 || adj > 63)
      else if (adj < -63 || adj > 63)
        {
        {
          fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB
          fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB
                          AS2 (sbci, r29, hi8(%d)) CR_TAB),
                          AS2 (sbci, r29, hi8(%d)) CR_TAB),
                   adj, adj);
                   adj, adj);
          size += 2;
          size += 2;
        }
        }
      else if (adj < 0)
      else if (adj < 0)
        {
        {
          fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
          fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj);
          size++;
          size++;
        }
        }
      else
      else
        {
        {
          fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
          fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj);
          size++;
          size++;
        }
        }
    }
    }
  return size;
  return size;
}
}
 
 
 
 
/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL,
   handling various cases of interrupt enable flag state BEFORE and AFTER
   handling various cases of interrupt enable flag state BEFORE and AFTER
   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
   (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags.
   Returns the number of instructions generated.  */
   Returns the number of instructions generated.  */
 
 
static int
static int
out_set_stack_ptr (FILE *file, int before, int after)
out_set_stack_ptr (FILE *file, int before, int after)
{
{
  int do_sph, do_cli, do_save, do_sei, lock_sph, size;
  int do_sph, do_cli, do_save, do_sei, lock_sph, size;
 
 
  /* The logic here is so that -mno-interrupts actually means
  /* The logic here is so that -mno-interrupts actually means
     "it is safe to write SPH in one instruction, then SPL in the
     "it is safe to write SPH in one instruction, then SPL in the
     next instruction, without disabling interrupts first".
     next instruction, without disabling interrupts first".
     The after != -1 case (interrupt/signal) is not affected.  */
     The after != -1 case (interrupt/signal) is not affected.  */
 
 
  do_sph = !TARGET_TINY_STACK;
  do_sph = !TARGET_TINY_STACK;
  lock_sph = do_sph && !TARGET_NO_INTERRUPTS;
  lock_sph = do_sph && !TARGET_NO_INTERRUPTS;
  do_cli = (before != 0 && (after == 0 || lock_sph));
  do_cli = (before != 0 && (after == 0 || lock_sph));
  do_save = (do_cli && before == -1 && after == -1);
  do_save = (do_cli && before == -1 && after == -1);
  do_sei = ((do_cli || before != 1) && after == 1);
  do_sei = ((do_cli || before != 1) && after == 1);
  size = 1;
  size = 1;
 
 
  if (do_save)
  if (do_save)
    {
    {
      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
      fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB);
      size++;
      size++;
    }
    }
 
 
  if (do_cli)
  if (do_cli)
    {
    {
      fprintf (file, "cli" CR_TAB);
      fprintf (file, "cli" CR_TAB);
      size++;
      size++;
    }
    }
 
 
  /* Do SPH first - maybe this will disable interrupts for one instruction
  /* Do SPH first - maybe this will disable interrupts for one instruction
     someday (a suggestion has been sent to avr@atmel.com for consideration
     someday (a suggestion has been sent to avr@atmel.com for consideration
     in future devices - that would make -mno-interrupts always safe).  */
     in future devices - that would make -mno-interrupts always safe).  */
  if (do_sph)
  if (do_sph)
    {
    {
      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
      fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB);
      size++;
      size++;
    }
    }
 
 
  /* Set/restore the I flag now - interrupts will be really enabled only
  /* Set/restore the I flag now - interrupts will be really enabled only
     after the next instruction.  This is not clearly documented, but
     after the next instruction.  This is not clearly documented, but
     believed to be true for all AVR devices.  */
     believed to be true for all AVR devices.  */
  if (do_save)
  if (do_save)
    {
    {
      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
      fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB);
      size++;
      size++;
    }
    }
  else if (do_sei)
  else if (do_sei)
    {
    {
      fprintf (file, "sei" CR_TAB);
      fprintf (file, "sei" CR_TAB);
      size++;
      size++;
    }
    }
 
 
  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
  fprintf (file, AS2 (out, __SP_L__, r28) "\n");
 
 
  return size;
  return size;
}
}
 
 
 
 
/* Output function prologue.  */
/* Output function prologue.  */
 
 
static void
static void
avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
avr_output_function_prologue (FILE *file, HOST_WIDE_INT size)
{
{
  int reg;
  int reg;
  int interrupt_func_p;
  int interrupt_func_p;
  int signal_func_p;
  int signal_func_p;
  int main_p;
  int main_p;
  int live_seq;
  int live_seq;
  int minimize;
  int minimize;
 
 
  last_insn_address = 0;
  last_insn_address = 0;
  jump_tables_size = 0;
  jump_tables_size = 0;
  prologue_size = 0;
  prologue_size = 0;
  fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
  fprintf (file, "/* prologue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n",
           size);
           size);
 
 
  if (avr_naked_function_p (current_function_decl))
  if (avr_naked_function_p (current_function_decl))
    {
    {
      fputs ("/* prologue: naked */\n", file);
      fputs ("/* prologue: naked */\n", file);
      goto out;
      goto out;
    }
    }
 
 
  interrupt_func_p = interrupt_function_p (current_function_decl);
  interrupt_func_p = interrupt_function_p (current_function_decl);
  signal_func_p = signal_function_p (current_function_decl);
  signal_func_p = signal_function_p (current_function_decl);
  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
  live_seq = sequent_regs_live ();
  live_seq = sequent_regs_live ();
  minimize = (TARGET_CALL_PROLOGUES
  minimize = (TARGET_CALL_PROLOGUES
              && !interrupt_func_p && !signal_func_p && live_seq);
              && !interrupt_func_p && !signal_func_p && live_seq);
 
 
  if (interrupt_func_p)
  if (interrupt_func_p)
    {
    {
      fprintf (file,"\tsei\n");
      fprintf (file,"\tsei\n");
      ++prologue_size;
      ++prologue_size;
    }
    }
  if (interrupt_func_p || signal_func_p)
  if (interrupt_func_p || signal_func_p)
    {
    {
      fprintf (file, "\t"
      fprintf (file, "\t"
               AS1 (push,__zero_reg__)   CR_TAB
               AS1 (push,__zero_reg__)   CR_TAB
               AS1 (push,__tmp_reg__)    CR_TAB
               AS1 (push,__tmp_reg__)    CR_TAB
               AS2 (in,__tmp_reg__,__SREG__) CR_TAB
               AS2 (in,__tmp_reg__,__SREG__) CR_TAB
               AS1 (push,__tmp_reg__)    CR_TAB
               AS1 (push,__tmp_reg__)    CR_TAB
               AS1 (clr,__zero_reg__)    "\n");
               AS1 (clr,__zero_reg__)    "\n");
      prologue_size += 5;
      prologue_size += 5;
    }
    }
  if (main_p)
  if (main_p)
    {
    {
      fprintf (file, ("\t"
      fprintf (file, ("\t"
                      AS1 (ldi,r28) ",lo8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS1 (ldi,r28) ",lo8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS1 (ldi,r29) ",hi8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS1 (ldi,r29) ",hi8(%s - " HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS2 (out,__SP_H__,r29)     CR_TAB
                      AS2 (out,__SP_H__,r29)     CR_TAB
                      AS2 (out,__SP_L__,r28) "\n"),
                      AS2 (out,__SP_L__,r28) "\n"),
               avr_init_stack, size, avr_init_stack, size);
               avr_init_stack, size, avr_init_stack, size);
 
 
      prologue_size += 4;
      prologue_size += 4;
    }
    }
  else if (minimize && (frame_pointer_needed || live_seq > 6))
  else if (minimize && (frame_pointer_needed || live_seq > 6))
    {
    {
      fprintf (file, ("\t"
      fprintf (file, ("\t"
                      AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS1 (ldi, r26) ",lo8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB
                      AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size);
                      AS1 (ldi, r27) ",hi8(" HOST_WIDE_INT_PRINT_DEC ")" CR_TAB), size, size);
 
 
      fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
      fputs ((AS2 (ldi,r30,pm_lo8(1f)) CR_TAB
              AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file);
              AS2 (ldi,r31,pm_hi8(1f)) CR_TAB), file);
 
 
      prologue_size += 4;
      prologue_size += 4;
 
 
      if (AVR_MEGA)
      if (AVR_MEGA)
        {
        {
          fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
          fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n",
                   (18 - live_seq) * 2);
                   (18 - live_seq) * 2);
          prologue_size += 2;
          prologue_size += 2;
        }
        }
      else
      else
        {
        {
          fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
          fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n",
                   (18 - live_seq) * 2);
                   (18 - live_seq) * 2);
          ++prologue_size;
          ++prologue_size;
        }
        }
      fputs ("1:\n", file);
      fputs ("1:\n", file);
    }
    }
  else
  else
    {
    {
      HARD_REG_SET set;
      HARD_REG_SET set;
 
 
      prologue_size += avr_regs_to_save (&set);
      prologue_size += avr_regs_to_save (&set);
      for (reg = 0; reg < 32; ++reg)
      for (reg = 0; reg < 32; ++reg)
        {
        {
          if (TEST_HARD_REG_BIT (set, reg))
          if (TEST_HARD_REG_BIT (set, reg))
            {
            {
              fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
              fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]);
            }
            }
        }
        }
      if (frame_pointer_needed)
      if (frame_pointer_needed)
        {
        {
          fprintf (file, "\t"
          fprintf (file, "\t"
                   AS1 (push,r28) CR_TAB
                   AS1 (push,r28) CR_TAB
                   AS1 (push,r29) CR_TAB
                   AS1 (push,r29) CR_TAB
                   AS2 (in,r28,__SP_L__) CR_TAB
                   AS2 (in,r28,__SP_L__) CR_TAB
                   AS2 (in,r29,__SP_H__) "\n");
                   AS2 (in,r29,__SP_H__) "\n");
          prologue_size += 4;
          prologue_size += 4;
          if (size)
          if (size)
            {
            {
              fputs ("\t", file);
              fputs ("\t", file);
              prologue_size += out_adj_frame_ptr (file, size);
              prologue_size += out_adj_frame_ptr (file, size);
 
 
              if (interrupt_func_p)
              if (interrupt_func_p)
                {
                {
                  prologue_size += out_set_stack_ptr (file, 1, 1);
                  prologue_size += out_set_stack_ptr (file, 1, 1);
                }
                }
              else if (signal_func_p)
              else if (signal_func_p)
                {
                {
                  prologue_size += out_set_stack_ptr (file, 0, 0);
                  prologue_size += out_set_stack_ptr (file, 0, 0);
                }
                }
              else
              else
                {
                {
                  prologue_size += out_set_stack_ptr (file, -1, -1);
                  prologue_size += out_set_stack_ptr (file, -1, -1);
                }
                }
            }
            }
        }
        }
    }
    }
 
 
 out:
 out:
  fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
  fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);
}
}
 
 
/* Output function epilogue.  */
/* Output function epilogue.  */
 
 
static void
static void
avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
avr_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
{
{
  int reg;
  int reg;
  int interrupt_func_p;
  int interrupt_func_p;
  int signal_func_p;
  int signal_func_p;
  int main_p;
  int main_p;
  int function_size;
  int function_size;
  int live_seq;
  int live_seq;
  int minimize;
  int minimize;
  rtx last = get_last_nonnote_insn ();
  rtx last = get_last_nonnote_insn ();
 
 
  function_size = jump_tables_size;
  function_size = jump_tables_size;
  if (last)
  if (last)
    {
    {
      rtx first = get_first_nonnote_insn ();
      rtx first = get_first_nonnote_insn ();
      function_size += (INSN_ADDRESSES (INSN_UID (last)) -
      function_size += (INSN_ADDRESSES (INSN_UID (last)) -
                        INSN_ADDRESSES (INSN_UID (first)));
                        INSN_ADDRESSES (INSN_UID (first)));
      function_size += get_attr_length (last);
      function_size += get_attr_length (last);
    }
    }
 
 
  fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", size);
  fprintf (file, "/* epilogue: frame size=" HOST_WIDE_INT_PRINT_DEC " */\n", size);
  epilogue_size = 0;
  epilogue_size = 0;
 
 
  if (avr_naked_function_p (current_function_decl))
  if (avr_naked_function_p (current_function_decl))
    {
    {
      fputs ("/* epilogue: naked */\n", file);
      fputs ("/* epilogue: naked */\n", file);
      goto out;
      goto out;
    }
    }
 
 
  if (last && GET_CODE (last) == BARRIER)
  if (last && GET_CODE (last) == BARRIER)
    {
    {
      fputs ("/* epilogue: noreturn */\n", file);
      fputs ("/* epilogue: noreturn */\n", file);
      goto out;
      goto out;
    }
    }
 
 
  interrupt_func_p = interrupt_function_p (current_function_decl);
  interrupt_func_p = interrupt_function_p (current_function_decl);
  signal_func_p = signal_function_p (current_function_decl);
  signal_func_p = signal_function_p (current_function_decl);
  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
  main_p = MAIN_NAME_P (DECL_NAME (current_function_decl));
  live_seq = sequent_regs_live ();
  live_seq = sequent_regs_live ();
  minimize = (TARGET_CALL_PROLOGUES
  minimize = (TARGET_CALL_PROLOGUES
              && !interrupt_func_p && !signal_func_p && live_seq);
              && !interrupt_func_p && !signal_func_p && live_seq);
 
 
  if (main_p)
  if (main_p)
    {
    {
      /* Return value from main() is already in the correct registers
      /* Return value from main() is already in the correct registers
         (r25:r24) as the exit() argument.  */
         (r25:r24) as the exit() argument.  */
      if (AVR_MEGA)
      if (AVR_MEGA)
        {
        {
          fputs ("\t" AS1 (jmp,exit) "\n", file);
          fputs ("\t" AS1 (jmp,exit) "\n", file);
          epilogue_size += 2;
          epilogue_size += 2;
        }
        }
      else
      else
        {
        {
          fputs ("\t" AS1 (rjmp,exit) "\n", file);
          fputs ("\t" AS1 (rjmp,exit) "\n", file);
          ++epilogue_size;
          ++epilogue_size;
        }
        }
    }
    }
  else if (minimize && (frame_pointer_needed || live_seq > 4))
  else if (minimize && (frame_pointer_needed || live_seq > 4))
    {
    {
      fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
      fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq);
      ++epilogue_size;
      ++epilogue_size;
      if (frame_pointer_needed)
      if (frame_pointer_needed)
        {
        {
          epilogue_size += out_adj_frame_ptr (file, -size);
          epilogue_size += out_adj_frame_ptr (file, -size);
        }
        }
      else
      else
        {
        {
          fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
          fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB
                          AS2 (in , r29, __SP_H__) CR_TAB));
                          AS2 (in , r29, __SP_H__) CR_TAB));
          epilogue_size += 2;
          epilogue_size += 2;
        }
        }
 
 
      if (AVR_MEGA)
      if (AVR_MEGA)
        {
        {
          fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
          fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n",
                   (18 - live_seq) * 2);
                   (18 - live_seq) * 2);
          epilogue_size += 2;
          epilogue_size += 2;
        }
        }
      else
      else
        {
        {
          fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
          fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n",
                   (18 - live_seq) * 2);
                   (18 - live_seq) * 2);
          ++epilogue_size;
          ++epilogue_size;
        }
        }
    }
    }
  else
  else
    {
    {
      HARD_REG_SET set;
      HARD_REG_SET set;
 
 
      if (frame_pointer_needed)
      if (frame_pointer_needed)
        {
        {
          if (size)
          if (size)
            {
            {
              fputs ("\t", file);
              fputs ("\t", file);
              epilogue_size += out_adj_frame_ptr (file, -size);
              epilogue_size += out_adj_frame_ptr (file, -size);
 
 
              if (interrupt_func_p || signal_func_p)
              if (interrupt_func_p || signal_func_p)
                {
                {
                  epilogue_size += out_set_stack_ptr (file, -1, 0);
                  epilogue_size += out_set_stack_ptr (file, -1, 0);
                }
                }
              else
              else
                {
                {
                  epilogue_size += out_set_stack_ptr (file, -1, -1);
                  epilogue_size += out_set_stack_ptr (file, -1, -1);
                }
                }
            }
            }
          fprintf (file, "\t"
          fprintf (file, "\t"
                   AS1 (pop,r29) CR_TAB
                   AS1 (pop,r29) CR_TAB
                   AS1 (pop,r28) "\n");
                   AS1 (pop,r28) "\n");
          epilogue_size += 2;
          epilogue_size += 2;
        }
        }
 
 
      epilogue_size += avr_regs_to_save (&set);
      epilogue_size += avr_regs_to_save (&set);
      for (reg = 31; reg >= 0; --reg)
      for (reg = 31; reg >= 0; --reg)
        {
        {
          if (TEST_HARD_REG_BIT (set, reg))
          if (TEST_HARD_REG_BIT (set, reg))
            {
            {
              fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
              fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]);
            }
            }
        }
        }
 
 
      if (interrupt_func_p || signal_func_p)
      if (interrupt_func_p || signal_func_p)
        {
        {
          fprintf (file, "\t"
          fprintf (file, "\t"
                   AS1 (pop,__tmp_reg__)      CR_TAB
                   AS1 (pop,__tmp_reg__)      CR_TAB
                   AS2 (out,__SREG__,__tmp_reg__) CR_TAB
                   AS2 (out,__SREG__,__tmp_reg__) CR_TAB
                   AS1 (pop,__tmp_reg__)      CR_TAB
                   AS1 (pop,__tmp_reg__)      CR_TAB
                   AS1 (pop,__zero_reg__)     "\n");
                   AS1 (pop,__zero_reg__)     "\n");
          epilogue_size += 4;
          epilogue_size += 4;
          fprintf (file, "\treti\n");
          fprintf (file, "\treti\n");
        }
        }
      else
      else
        fprintf (file, "\tret\n");
        fprintf (file, "\tret\n");
      ++epilogue_size;
      ++epilogue_size;
    }
    }
 
 
 out:
 out:
  fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
  fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size);
  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name (),
  fprintf (file, "/* function %s size %d (%d) */\n", current_function_name (),
           prologue_size + function_size + epilogue_size, function_size);
           prologue_size + function_size + epilogue_size, function_size);
  commands_in_file += prologue_size + function_size + epilogue_size;
  commands_in_file += prologue_size + function_size + epilogue_size;
  commands_in_prologues += prologue_size;
  commands_in_prologues += prologue_size;
  commands_in_epilogues += epilogue_size;
  commands_in_epilogues += epilogue_size;
}
}
 
 
 
 
/* Return nonzero if X (an RTX) is a legitimate memory address on the target
/* Return nonzero if X (an RTX) is a legitimate memory address on the target
   machine for a memory operand of mode MODE.  */
   machine for a memory operand of mode MODE.  */
 
 
int
int
legitimate_address_p (enum machine_mode mode, rtx x, int strict)
legitimate_address_p (enum machine_mode mode, rtx x, int strict)
{
{
  enum reg_class r = NO_REGS;
  enum reg_class r = NO_REGS;
 
 
  if (TARGET_ALL_DEBUG)
  if (TARGET_ALL_DEBUG)
    {
    {
      fprintf (stderr, "mode: (%s) %s %s %s %s:",
      fprintf (stderr, "mode: (%s) %s %s %s %s:",
               GET_MODE_NAME(mode),
               GET_MODE_NAME(mode),
               strict ? "(strict)": "",
               strict ? "(strict)": "",
               reload_completed ? "(reload_completed)": "",
               reload_completed ? "(reload_completed)": "",
               reload_in_progress ? "(reload_in_progress)": "",
               reload_in_progress ? "(reload_in_progress)": "",
               reg_renumber ? "(reg_renumber)" : "");
               reg_renumber ? "(reg_renumber)" : "");
      if (GET_CODE (x) == PLUS
      if (GET_CODE (x) == PLUS
          && REG_P (XEXP (x, 0))
          && REG_P (XEXP (x, 0))
          && GET_CODE (XEXP (x, 1)) == CONST_INT
          && GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) >= 0
          && INTVAL (XEXP (x, 1)) >= 0
          && INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode)
          && INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode)
          && reg_renumber
          && reg_renumber
          )
          )
        fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
        fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)),
                 true_regnum (XEXP (x, 0)));
                 true_regnum (XEXP (x, 0)));
      debug_rtx (x);
      debug_rtx (x);
    }
    }
  if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
  if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x)
                    : REG_OK_FOR_BASE_NOSTRICT_P (x)))
                    : REG_OK_FOR_BASE_NOSTRICT_P (x)))
    r = POINTER_REGS;
    r = POINTER_REGS;
  else if (CONSTANT_ADDRESS_P (x))
  else if (CONSTANT_ADDRESS_P (x))
    r = ALL_REGS;
    r = ALL_REGS;
  else if (GET_CODE (x) == PLUS
  else if (GET_CODE (x) == PLUS
           && REG_P (XEXP (x, 0))
           && REG_P (XEXP (x, 0))
           && GET_CODE (XEXP (x, 1)) == CONST_INT
           && GET_CODE (XEXP (x, 1)) == CONST_INT
           && INTVAL (XEXP (x, 1)) >= 0)
           && INTVAL (XEXP (x, 1)) >= 0)
    {
    {
      int fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode);
      int fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode);
      if (fit)
      if (fit)
        {
        {
          if (! strict
          if (! strict
              || REGNO (XEXP (x,0)) == REG_Y
              || REGNO (XEXP (x,0)) == REG_Y
              || REGNO (XEXP (x,0)) == REG_Z)
              || REGNO (XEXP (x,0)) == REG_Z)
            r = BASE_POINTER_REGS;
            r = BASE_POINTER_REGS;
          if (XEXP (x,0) == frame_pointer_rtx
          if (XEXP (x,0) == frame_pointer_rtx
              || XEXP (x,0) == arg_pointer_rtx)
              || XEXP (x,0) == arg_pointer_rtx)
            r = BASE_POINTER_REGS;
            r = BASE_POINTER_REGS;
        }
        }
      else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
      else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx)
        r = POINTER_Y_REGS;
        r = POINTER_Y_REGS;
    }
    }
  else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
  else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
           && REG_P (XEXP (x, 0))
           && REG_P (XEXP (x, 0))
           && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
           && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0))
               : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
               : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0))))
    {
    {
      r = POINTER_REGS;
      r = POINTER_REGS;
    }
    }
  if (TARGET_ALL_DEBUG)
  if (TARGET_ALL_DEBUG)
    {
    {
      fprintf (stderr, "   ret = %c\n", r + '0');
      fprintf (stderr, "   ret = %c\n", r + '0');
    }
    }
  return r == NO_REGS ? 0 : (int)r;
  return r == NO_REGS ? 0 : (int)r;
}
}
 
 
/* Attempts to replace X with a valid
/* Attempts to replace X with a valid
   memory address for an operand of mode MODE  */
   memory address for an operand of mode MODE  */
 
 
rtx
rtx
legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
{
{
  x = oldx;
  x = oldx;
  if (TARGET_ALL_DEBUG)
  if (TARGET_ALL_DEBUG)
    {
    {
      fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode));
      fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode));
      debug_rtx (oldx);
      debug_rtx (oldx);
    }
    }
 
 
  if (GET_CODE (oldx) == PLUS
  if (GET_CODE (oldx) == PLUS
      && REG_P (XEXP (oldx,0)))
      && REG_P (XEXP (oldx,0)))
    {
    {
      if (REG_P (XEXP (oldx,1)))
      if (REG_P (XEXP (oldx,1)))
        x = force_reg (GET_MODE (oldx), oldx);
        x = force_reg (GET_MODE (oldx), oldx);
      else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT)
      else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT)
        {
        {
          int offs = INTVAL (XEXP (oldx,1));
          int offs = INTVAL (XEXP (oldx,1));
          if (frame_pointer_rtx != XEXP (oldx,0))
          if (frame_pointer_rtx != XEXP (oldx,0))
            if (offs > MAX_LD_OFFSET (mode))
            if (offs > MAX_LD_OFFSET (mode))
              {
              {
                if (TARGET_ALL_DEBUG)
                if (TARGET_ALL_DEBUG)
                  fprintf (stderr, "force_reg (big offset)\n");
                  fprintf (stderr, "force_reg (big offset)\n");
                x = force_reg (GET_MODE (oldx), oldx);
                x = force_reg (GET_MODE (oldx), oldx);
              }
              }
        }
        }
    }
    }
  return x;
  return x;
}
}
 
 
 
 
/* Return a pointer register name as a string.  */
/* Return a pointer register name as a string.  */
 
 
static const char *
static const char *
ptrreg_to_str (int regno)
ptrreg_to_str (int regno)
{
{
  switch (regno)
  switch (regno)
    {
    {
    case REG_X: return "X";
    case REG_X: return "X";
    case REG_Y: return "Y";
    case REG_Y: return "Y";
    case REG_Z: return "Z";
    case REG_Z: return "Z";
    default:
    default:
      output_operand_lossage ("address operand requires constraint for X, Y, or Z register");
      output_operand_lossage ("address operand requires constraint for X, Y, or Z register");
    }
    }
  return NULL;
  return NULL;
}
}
 
 
/* Return the condition name as a string.
/* Return the condition name as a string.
   Used in conditional jump constructing  */
   Used in conditional jump constructing  */
 
 
static const char *
static const char *
cond_string (enum rtx_code code)
cond_string (enum rtx_code code)
{
{
  switch (code)
  switch (code)
    {
    {
    case NE:
    case NE:
      return "ne";
      return "ne";
    case EQ:
    case EQ:
      return "eq";
      return "eq";
    case GE:
    case GE:
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
        return "pl";
        return "pl";
      else
      else
        return "ge";
        return "ge";
    case LT:
    case LT:
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
        return "mi";
        return "mi";
      else
      else
        return "lt";
        return "lt";
    case GEU:
    case GEU:
      return "sh";
      return "sh";
    case LTU:
    case LTU:
      return "lo";
      return "lo";
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
}
}
 
 
/* Output ADDR to FILE as address.  */
/* Output ADDR to FILE as address.  */
 
 
void
void
print_operand_address (FILE *file, rtx addr)
print_operand_address (FILE *file, rtx addr)
{
{
  switch (GET_CODE (addr))
  switch (GET_CODE (addr))
    {
    {
    case REG:
    case REG:
      fprintf (file, ptrreg_to_str (REGNO (addr)));
      fprintf (file, ptrreg_to_str (REGNO (addr)));
      break;
      break;
 
 
    case PRE_DEC:
    case PRE_DEC:
      fprintf (file, "-%s", ptrreg_to_str (REGNO (XEXP (addr, 0))));
      fprintf (file, "-%s", ptrreg_to_str (REGNO (XEXP (addr, 0))));
      break;
      break;
 
 
    case POST_INC:
    case POST_INC:
      fprintf (file, "%s+", ptrreg_to_str (REGNO (XEXP (addr, 0))));
      fprintf (file, "%s+", ptrreg_to_str (REGNO (XEXP (addr, 0))));
      break;
      break;
 
 
    default:
    default:
      if (CONSTANT_ADDRESS_P (addr)
      if (CONSTANT_ADDRESS_P (addr)
          && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (addr))
          && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (addr))
              || GET_CODE (addr) == LABEL_REF))
              || GET_CODE (addr) == LABEL_REF))
        {
        {
          fprintf (file, "pm(");
          fprintf (file, "pm(");
          output_addr_const (file,addr);
          output_addr_const (file,addr);
          fprintf (file ,")");
          fprintf (file ,")");
        }
        }
      else
      else
        output_addr_const (file, addr);
        output_addr_const (file, addr);
    }
    }
}
}
 
 
 
 
/* Output X as assembler operand to file FILE.  */
/* Output X as assembler operand to file FILE.  */
 
 
void
void
print_operand (FILE *file, rtx x, int code)
print_operand (FILE *file, rtx x, int code)
{
{
  int abcd = 0;
  int abcd = 0;
 
 
  if (code >= 'A' && code <= 'D')
  if (code >= 'A' && code <= 'D')
    abcd = code - 'A';
    abcd = code - 'A';
 
 
  if (code == '~')
  if (code == '~')
    {
    {
      if (!AVR_MEGA)
      if (!AVR_MEGA)
        fputc ('r', file);
        fputc ('r', file);
    }
    }
  else if (REG_P (x))
  else if (REG_P (x))
    {
    {
      if (x == zero_reg_rtx)
      if (x == zero_reg_rtx)
        fprintf (file, "__zero_reg__");
        fprintf (file, "__zero_reg__");
      else
      else
        fprintf (file, reg_names[true_regnum (x) + abcd]);
        fprintf (file, reg_names[true_regnum (x) + abcd]);
    }
    }
  else if (GET_CODE (x) == CONST_INT)
  else if (GET_CODE (x) == CONST_INT)
    fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + abcd);
    fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) + abcd);
  else if (GET_CODE (x) == MEM)
  else if (GET_CODE (x) == MEM)
    {
    {
      rtx addr = XEXP (x,0);
      rtx addr = XEXP (x,0);
 
 
      if (CONSTANT_P (addr) && abcd)
      if (CONSTANT_P (addr) && abcd)
        {
        {
          fputc ('(', file);
          fputc ('(', file);
          output_address (addr);
          output_address (addr);
          fprintf (file, ")+%d", abcd);
          fprintf (file, ")+%d", abcd);
        }
        }
      else if (code == 'o')
      else if (code == 'o')
        {
        {
          if (GET_CODE (addr) != PLUS)
          if (GET_CODE (addr) != PLUS)
            fatal_insn ("bad address, not (reg+disp):", addr);
            fatal_insn ("bad address, not (reg+disp):", addr);
 
 
          print_operand (file, XEXP (addr, 1), 0);
          print_operand (file, XEXP (addr, 1), 0);
        }
        }
      else if (code == 'p' || code == 'r')
      else if (code == 'p' || code == 'r')
        {
        {
          if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC)
          if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC)
            fatal_insn ("bad address, not post_inc or pre_dec:", addr);
            fatal_insn ("bad address, not post_inc or pre_dec:", addr);
 
 
          if (code == 'p')
          if (code == 'p')
            print_operand_address (file, XEXP (addr, 0));  /* X, Y, Z */
            print_operand_address (file, XEXP (addr, 0));  /* X, Y, Z */
          else
          else
            print_operand (file, XEXP (addr, 0), 0);  /* r26, r28, r30 */
            print_operand (file, XEXP (addr, 0), 0);  /* r26, r28, r30 */
        }
        }
      else if (GET_CODE (addr) == PLUS)
      else if (GET_CODE (addr) == PLUS)
        {
        {
          print_operand_address (file, XEXP (addr,0));
          print_operand_address (file, XEXP (addr,0));
          if (REGNO (XEXP (addr, 0)) == REG_X)
          if (REGNO (XEXP (addr, 0)) == REG_X)
            fatal_insn ("internal compiler error.  Bad address:"
            fatal_insn ("internal compiler error.  Bad address:"
                        ,addr);
                        ,addr);
          fputc ('+', file);
          fputc ('+', file);
          print_operand (file, XEXP (addr,1), code);
          print_operand (file, XEXP (addr,1), code);
        }
        }
      else
      else
        print_operand_address (file, addr);
        print_operand_address (file, addr);
    }
    }
  else if (GET_CODE (x) == CONST_DOUBLE)
  else if (GET_CODE (x) == CONST_DOUBLE)
    {
    {
      long val;
      long val;
      REAL_VALUE_TYPE rv;
      REAL_VALUE_TYPE rv;
      if (GET_MODE (x) != SFmode)
      if (GET_MODE (x) != SFmode)
        fatal_insn ("internal compiler error.  Unknown mode:", x);
        fatal_insn ("internal compiler error.  Unknown mode:", x);
      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
      REAL_VALUE_TO_TARGET_SINGLE (rv, val);
      REAL_VALUE_TO_TARGET_SINGLE (rv, val);
      fprintf (file, "0x%lx", val);
      fprintf (file, "0x%lx", val);
    }
    }
  else if (code == 'j')
  else if (code == 'j')
    fputs (cond_string (GET_CODE (x)), file);
    fputs (cond_string (GET_CODE (x)), file);
  else if (code == 'k')
  else if (code == 'k')
    fputs (cond_string (reverse_condition (GET_CODE (x))), file);
    fputs (cond_string (reverse_condition (GET_CODE (x))), file);
  else
  else
    print_operand_address (file, x);
    print_operand_address (file, x);
}
}
 
 
/* Recognize operand OP of mode MODE used in call instructions.  */
/* Recognize operand OP of mode MODE used in call instructions.  */
 
 
int
int
call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
{
  if (GET_CODE (op) == MEM)
  if (GET_CODE (op) == MEM)
    {
    {
      rtx inside = XEXP (op, 0);
      rtx inside = XEXP (op, 0);
      if (register_operand (inside, Pmode))
      if (register_operand (inside, Pmode))
        return 1;
        return 1;
      if (CONSTANT_ADDRESS_P (inside))
      if (CONSTANT_ADDRESS_P (inside))
        return 1;
        return 1;
    }
    }
  return 0;
  return 0;
}
}
 
 
/* Update the condition code in the INSN.  */
/* Update the condition code in the INSN.  */
 
 
void
void
notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
{
{
  rtx set;
  rtx set;
 
 
  switch (get_attr_cc (insn))
  switch (get_attr_cc (insn))
    {
    {
    case CC_NONE:
    case CC_NONE:
      /* Insn does not affect CC at all.  */
      /* Insn does not affect CC at all.  */
      break;
      break;
 
 
    case CC_SET_N:
    case CC_SET_N:
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      break;
      break;
 
 
    case CC_SET_ZN:
    case CC_SET_ZN:
      set = single_set (insn);
      set = single_set (insn);
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      if (set)
      if (set)
        {
        {
          cc_status.flags |= CC_NO_OVERFLOW;
          cc_status.flags |= CC_NO_OVERFLOW;
          cc_status.value1 = SET_DEST (set);
          cc_status.value1 = SET_DEST (set);
        }
        }
      break;
      break;
 
 
    case CC_SET_CZN:
    case CC_SET_CZN:
      /* Insn sets the Z,N,C flags of CC to recog_operand[0].
      /* 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
         The V flag may or may not be known but that's ok because
         alter_cond will change tests to use EQ/NE.  */
         alter_cond will change tests to use EQ/NE.  */
      set = single_set (insn);
      set = single_set (insn);
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      if (set)
      if (set)
        {
        {
          cc_status.value1 = SET_DEST (set);
          cc_status.value1 = SET_DEST (set);
          cc_status.flags |= CC_OVERFLOW_UNUSABLE;
          cc_status.flags |= CC_OVERFLOW_UNUSABLE;
        }
        }
      break;
      break;
 
 
    case CC_COMPARE:
    case CC_COMPARE:
      set = single_set (insn);
      set = single_set (insn);
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      if (set)
      if (set)
        cc_status.value1 = SET_SRC (set);
        cc_status.value1 = SET_SRC (set);
      break;
      break;
 
 
    case CC_CLOBBER:
    case CC_CLOBBER:
      /* Insn doesn't leave CC in a usable state.  */
      /* Insn doesn't leave CC in a usable state.  */
      CC_STATUS_INIT;
      CC_STATUS_INIT;
 
 
      /* Correct CC for the ashrqi3 with the shift count as CONST_INT != 6 */
      /* Correct CC for the ashrqi3 with the shift count as CONST_INT != 6 */
      set = single_set (insn);
      set = single_set (insn);
      if (set)
      if (set)
        {
        {
          rtx src = SET_SRC (set);
          rtx src = SET_SRC (set);
 
 
          if (GET_CODE (src) == ASHIFTRT
          if (GET_CODE (src) == ASHIFTRT
              && GET_MODE (src) == QImode)
              && GET_MODE (src) == QImode)
            {
            {
              rtx x = XEXP (src, 1);
              rtx x = XEXP (src, 1);
 
 
              if (GET_CODE (x) == CONST_INT
              if (GET_CODE (x) == CONST_INT
                  && INTVAL (x) > 0
                  && INTVAL (x) > 0
                  && INTVAL (x) != 6)
                  && INTVAL (x) != 6)
                {
                {
                  cc_status.value1 = SET_DEST (set);
                  cc_status.value1 = SET_DEST (set);
                  cc_status.flags |= CC_OVERFLOW_UNUSABLE;
                  cc_status.flags |= CC_OVERFLOW_UNUSABLE;
                }
                }
            }
            }
        }
        }
      break;
      break;
    }
    }
}
}
 
 
/* Return maximum number of consecutive registers of
/* Return maximum number of consecutive registers of
   class CLASS needed to hold a value of mode MODE.  */
   class CLASS needed to hold a value of mode MODE.  */
 
 
int
int
class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,enum machine_mode mode)
class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED,enum machine_mode mode)
{
{
  return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
  return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
}
}
 
 
/* Choose mode for jump insn:
/* Choose mode for jump insn:
   1 - relative jump in range -63 <= x <= 62 ;
   1 - relative jump in range -63 <= x <= 62 ;
   2 - relative jump in range -2046 <= x <= 2045 ;
   2 - relative jump in range -2046 <= x <= 2045 ;
   3 - absolute jump (only for ATmega[16]03).  */
   3 - absolute jump (only for ATmega[16]03).  */
 
 
int
int
avr_jump_mode (rtx x, rtx insn)
avr_jump_mode (rtx x, rtx insn)
{
{
  int dest_addr = INSN_ADDRESSES (INSN_UID (GET_MODE (x) == LABEL_REF
  int dest_addr = INSN_ADDRESSES (INSN_UID (GET_MODE (x) == LABEL_REF
                                            ? XEXP (x, 0) : x));
                                            ? XEXP (x, 0) : x));
  int cur_addr = INSN_ADDRESSES (INSN_UID (insn));
  int cur_addr = INSN_ADDRESSES (INSN_UID (insn));
  int jump_distance = cur_addr - dest_addr;
  int jump_distance = cur_addr - dest_addr;
 
 
  if (-63 <= jump_distance && jump_distance <= 62)
  if (-63 <= jump_distance && jump_distance <= 62)
    return 1;
    return 1;
  else if (-2046 <= jump_distance && jump_distance <= 2045)
  else if (-2046 <= jump_distance && jump_distance <= 2045)
    return 2;
    return 2;
  else if (AVR_MEGA)
  else if (AVR_MEGA)
    return 3;
    return 3;
 
 
  return 2;
  return 2;
}
}
 
 
/* return an AVR condition jump commands.
/* return an AVR condition jump commands.
   X is a comparison RTX.
   X is a comparison RTX.
   LEN is a number returned by avr_jump_mode function.
   LEN is a number returned by avr_jump_mode function.
   if REVERSE nonzero then condition code in X must be reversed.  */
   if REVERSE nonzero then condition code in X must be reversed.  */
 
 
const char *
const char *
ret_cond_branch (rtx x, int len, int reverse)
ret_cond_branch (rtx x, int len, int reverse)
{
{
  RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
  RTX_CODE cond = reverse ? reverse_condition (GET_CODE (x)) : GET_CODE (x);
 
 
  switch (cond)
  switch (cond)
    {
    {
    case GT:
    case GT:
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
        return (len == 1 ? (AS1 (breq,.+2) CR_TAB
        return (len == 1 ? (AS1 (breq,.+2) CR_TAB
                            AS1 (brpl,%0)) :
                            AS1 (brpl,%0)) :
                len == 2 ? (AS1 (breq,.+4) CR_TAB
                len == 2 ? (AS1 (breq,.+4) CR_TAB
                            AS1 (brmi,.+2) CR_TAB
                            AS1 (brmi,.+2) CR_TAB
                            AS1 (rjmp,%0)) :
                            AS1 (rjmp,%0)) :
                (AS1 (breq,.+6) CR_TAB
                (AS1 (breq,.+6) CR_TAB
                 AS1 (brmi,.+4) CR_TAB
                 AS1 (brmi,.+4) CR_TAB
                 AS1 (jmp,%0)));
                 AS1 (jmp,%0)));
 
 
      else
      else
        return (len == 1 ? (AS1 (breq,.+2) CR_TAB
        return (len == 1 ? (AS1 (breq,.+2) CR_TAB
                            AS1 (brge,%0)) :
                            AS1 (brge,%0)) :
                len == 2 ? (AS1 (breq,.+4) CR_TAB
                len == 2 ? (AS1 (breq,.+4) CR_TAB
                            AS1 (brlt,.+2) CR_TAB
                            AS1 (brlt,.+2) CR_TAB
                            AS1 (rjmp,%0)) :
                            AS1 (rjmp,%0)) :
                (AS1 (breq,.+6) CR_TAB
                (AS1 (breq,.+6) CR_TAB
                 AS1 (brlt,.+4) CR_TAB
                 AS1 (brlt,.+4) CR_TAB
                 AS1 (jmp,%0)));
                 AS1 (jmp,%0)));
    case GTU:
    case GTU:
      return (len == 1 ? (AS1 (breq,.+2) CR_TAB
      return (len == 1 ? (AS1 (breq,.+2) CR_TAB
                          AS1 (brsh,%0)) :
                          AS1 (brsh,%0)) :
              len == 2 ? (AS1 (breq,.+4) CR_TAB
              len == 2 ? (AS1 (breq,.+4) CR_TAB
                          AS1 (brlo,.+2) CR_TAB
                          AS1 (brlo,.+2) CR_TAB
                          AS1 (rjmp,%0)) :
                          AS1 (rjmp,%0)) :
              (AS1 (breq,.+6) CR_TAB
              (AS1 (breq,.+6) CR_TAB
               AS1 (brlo,.+4) CR_TAB
               AS1 (brlo,.+4) CR_TAB
               AS1 (jmp,%0)));
               AS1 (jmp,%0)));
    case LE:
    case LE:
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
      if (cc_prev_status.flags & CC_OVERFLOW_UNUSABLE)
        return (len == 1 ? (AS1 (breq,%0) CR_TAB
        return (len == 1 ? (AS1 (breq,%0) CR_TAB
                            AS1 (brmi,%0)) :
                            AS1 (brmi,%0)) :
                len == 2 ? (AS1 (breq,.+2) CR_TAB
                len == 2 ? (AS1 (breq,.+2) CR_TAB
                            AS1 (brpl,.+2) CR_TAB
                            AS1 (brpl,.+2) CR_TAB
                            AS1 (rjmp,%0)) :
                            AS1 (rjmp,%0)) :
                (AS1 (breq,.+2) CR_TAB
                (AS1 (breq,.+2) CR_TAB
                 AS1 (brpl,.+4) CR_TAB
                 AS1 (brpl,.+4) CR_TAB
                 AS1 (jmp,%0)));
                 AS1 (jmp,%0)));
      else
      else
        return (len == 1 ? (AS1 (breq,%0) CR_TAB
        return (len == 1 ? (AS1 (breq,%0) CR_TAB
                            AS1 (brlt,%0)) :
                            AS1 (brlt,%0)) :
                len == 2 ? (AS1 (breq,.+2) CR_TAB
                len == 2 ? (AS1 (breq,.+2) CR_TAB
                            AS1 (brge,.+2) CR_TAB
                            AS1 (brge,.+2) CR_TAB
                            AS1 (rjmp,%0)) :
                            AS1 (rjmp,%0)) :
                (AS1 (breq,.+2) CR_TAB
                (AS1 (breq,.+2) CR_TAB
                 AS1 (brge,.+4) CR_TAB
                 AS1 (brge,.+4) CR_TAB
                 AS1 (jmp,%0)));
                 AS1 (jmp,%0)));
    case LEU:
    case LEU:
      return (len == 1 ? (AS1 (breq,%0) CR_TAB
      return (len == 1 ? (AS1 (breq,%0) CR_TAB
                          AS1 (brlo,%0)) :
                          AS1 (brlo,%0)) :
              len == 2 ? (AS1 (breq,.+2) CR_TAB
              len == 2 ? (AS1 (breq,.+2) CR_TAB
                          AS1 (brsh,.+2) CR_TAB
                          AS1 (brsh,.+2) CR_TAB
                          AS1 (rjmp,%0)) :
                          AS1 (rjmp,%0)) :
              (AS1 (breq,.+2) CR_TAB
              (AS1 (breq,.+2) CR_TAB
               AS1 (brsh,.+4) CR_TAB
               AS1 (brsh,.+4) CR_TAB
               AS1 (jmp,%0)));
               AS1 (jmp,%0)));
    default:
    default:
      if (reverse)
      if (reverse)
        {
        {
          switch (len)
          switch (len)
            {
            {
            case 1:
            case 1:
              return AS1 (br%k1,%0);
              return AS1 (br%k1,%0);
            case 2:
            case 2:
              return (AS1 (br%j1,.+2) CR_TAB
              return (AS1 (br%j1,.+2) CR_TAB
                      AS1 (rjmp,%0));
                      AS1 (rjmp,%0));
            default:
            default:
              return (AS1 (br%j1,.+4) CR_TAB
              return (AS1 (br%j1,.+4) CR_TAB
                      AS1 (jmp,%0));
                      AS1 (jmp,%0));
            }
            }
        }
        }
        else
        else
          {
          {
            switch (len)
            switch (len)
              {
              {
              case 1:
              case 1:
                return AS1 (br%j1,%0);
                return AS1 (br%j1,%0);
              case 2:
              case 2:
                return (AS1 (br%k1,.+2) CR_TAB
                return (AS1 (br%k1,.+2) CR_TAB
                        AS1 (rjmp,%0));
                        AS1 (rjmp,%0));
              default:
              default:
                return (AS1 (br%k1,.+4) CR_TAB
                return (AS1 (br%k1,.+4) CR_TAB
                        AS1 (jmp,%0));
                        AS1 (jmp,%0));
              }
              }
          }
          }
    }
    }
  return "";
  return "";
}
}
 
 
/* Predicate function for immediate operand which fits to byte (8bit) */
/* Predicate function for immediate operand which fits to byte (8bit) */
 
 
int
int
byte_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
byte_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
{
  return (GET_CODE (op) == CONST_INT
  return (GET_CODE (op) == CONST_INT
          && INTVAL (op) <= 0xff && INTVAL (op) >= 0);
          && INTVAL (op) <= 0xff && INTVAL (op) >= 0);
}
}
 
 
/* Output all insn addresses and their sizes into the assembly language
/* Output all insn addresses and their sizes into the assembly language
   output file.  This is helpful for debugging whether the length attributes
   output file.  This is helpful for debugging whether the length attributes
   in the md file are correct.
   in the md file are correct.
   Output insn cost for next insn.  */
   Output insn cost for next insn.  */
 
 
void
void
final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED,
final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED,
                    int num_operands ATTRIBUTE_UNUSED)
                    int num_operands ATTRIBUTE_UNUSED)
{
{
  int uid = INSN_UID (insn);
  int uid = INSN_UID (insn);
 
 
  if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
  if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
    {
    {
      fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n",
      fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n",
               INSN_ADDRESSES (uid),
               INSN_ADDRESSES (uid),
               INSN_ADDRESSES (uid) - last_insn_address,
               INSN_ADDRESSES (uid) - last_insn_address,
               rtx_cost (PATTERN (insn), INSN));
               rtx_cost (PATTERN (insn), INSN));
    }
    }
  last_insn_address = INSN_ADDRESSES (uid);
  last_insn_address = INSN_ADDRESSES (uid);
}
}
 
 
/* Return 0 if undefined, 1 if always true or always false.  */
/* Return 0 if undefined, 1 if always true or always false.  */
 
 
int
int
avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE operator, rtx x)
avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE operator, rtx x)
{
{
  unsigned int max = (mode == QImode ? 0xff :
  unsigned int max = (mode == QImode ? 0xff :
                      mode == HImode ? 0xffff :
                      mode == HImode ? 0xffff :
                      mode == SImode ? 0xffffffff : 0);
                      mode == SImode ? 0xffffffff : 0);
  if (max && operator && GET_CODE (x) == CONST_INT)
  if (max && operator && GET_CODE (x) == CONST_INT)
    {
    {
      if (unsigned_condition (operator) != operator)
      if (unsigned_condition (operator) != operator)
        max >>= 1;
        max >>= 1;
 
 
      if (max != (INTVAL (x) & max)
      if (max != (INTVAL (x) & max)
          && INTVAL (x) != 0xff)
          && INTVAL (x) != 0xff)
        return 1;
        return 1;
    }
    }
  return 0;
  return 0;
}
}
 
 
 
 
/* Returns nonzero if REGNO is the number of a hard
/* Returns nonzero if REGNO is the number of a hard
   register in which function arguments are sometimes passed.  */
   register in which function arguments are sometimes passed.  */
 
 
int
int
function_arg_regno_p(int r)
function_arg_regno_p(int r)
{
{
  return (r >= 8 && r <= 25);
  return (r >= 8 && r <= 25);
}
}
 
 
/* Initializing the variable cum for the state at the beginning
/* Initializing the variable cum for the state at the beginning
   of the argument list.  */
   of the argument list.  */
 
 
void
void
init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname,
                      tree fndecl ATTRIBUTE_UNUSED)
                      tree fndecl ATTRIBUTE_UNUSED)
{
{
  cum->nregs = 18;
  cum->nregs = 18;
  cum->regno = FIRST_CUM_REG;
  cum->regno = FIRST_CUM_REG;
  if (!libname && fntype)
  if (!libname && fntype)
    {
    {
      int stdarg = (TYPE_ARG_TYPES (fntype) != 0
      int stdarg = (TYPE_ARG_TYPES (fntype) != 0
                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
                    && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
                        != void_type_node));
                        != void_type_node));
      if (stdarg)
      if (stdarg)
        cum->nregs = 0;
        cum->nregs = 0;
    }
    }
}
}
 
 
/* Returns the number of registers to allocate for a function argument.  */
/* Returns the number of registers to allocate for a function argument.  */
 
 
static int
static int
avr_num_arg_regs (enum machine_mode mode, tree type)
avr_num_arg_regs (enum machine_mode mode, tree type)
{
{
  int size;
  int size;
 
 
  if (mode == BLKmode)
  if (mode == BLKmode)
    size = int_size_in_bytes (type);
    size = int_size_in_bytes (type);
  else
  else
    size = GET_MODE_SIZE (mode);
    size = GET_MODE_SIZE (mode);
 
 
  /* Align all function arguments to start in even-numbered registers.
  /* Align all function arguments to start in even-numbered registers.
     Odd-sized arguments leave holes above them.  */
     Odd-sized arguments leave holes above them.  */
 
 
  return (size + 1) & ~1;
  return (size + 1) & ~1;
}
}
 
 
/* Controls whether a function argument is passed
/* Controls whether a function argument is passed
   in a register, and which register.  */
   in a register, and which register.  */
 
 
rtx
rtx
function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
              int named ATTRIBUTE_UNUSED)
              int named ATTRIBUTE_UNUSED)
{
{
  int bytes = avr_num_arg_regs (mode, type);
  int bytes = avr_num_arg_regs (mode, type);
 
 
  if (cum->nregs && bytes <= cum->nregs)
  if (cum->nregs && bytes <= cum->nregs)
    return gen_rtx_REG (mode, cum->regno - bytes);
    return gen_rtx_REG (mode, cum->regno - bytes);
 
 
  return NULL_RTX;
  return NULL_RTX;
}
}
 
 
/* Update the summarizer variable CUM to advance past an argument
/* Update the summarizer variable CUM to advance past an argument
   in the argument list.  */
   in the argument list.  */
 
 
void
void
function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
                      int named ATTRIBUTE_UNUSED)
                      int named ATTRIBUTE_UNUSED)
{
{
  int bytes = avr_num_arg_regs (mode, type);
  int bytes = avr_num_arg_regs (mode, type);
 
 
  cum->nregs -= bytes;
  cum->nregs -= bytes;
  cum->regno -= bytes;
  cum->regno -= bytes;
 
 
  if (cum->nregs <= 0)
  if (cum->nregs <= 0)
    {
    {
      cum->nregs = 0;
      cum->nregs = 0;
      cum->regno = FIRST_CUM_REG;
      cum->regno = FIRST_CUM_REG;
    }
    }
}
}
 
 
/***********************************************************************
/***********************************************************************
  Functions for outputting various mov's for a various modes
  Functions for outputting various mov's for a various modes
************************************************************************/
************************************************************************/
const char *
const char *
output_movqi (rtx insn, rtx operands[], int *l)
output_movqi (rtx insn, rtx operands[], int *l)
{
{
  int dummy;
  int dummy;
  rtx dest = operands[0];
  rtx dest = operands[0];
  rtx src = operands[1];
  rtx src = operands[1];
  int *real_l = l;
  int *real_l = l;
 
 
  if (!l)
  if (!l)
    l = &dummy;
    l = &dummy;
 
 
  *l = 1;
  *l = 1;
 
 
  if (register_operand (dest, QImode))
  if (register_operand (dest, QImode))
    {
    {
      if (register_operand (src, QImode)) /* mov r,r */
      if (register_operand (src, QImode)) /* mov r,r */
        {
        {
          if (test_hard_reg_class (STACK_REG, dest))
          if (test_hard_reg_class (STACK_REG, dest))
            return AS2 (out,%0,%1);
            return AS2 (out,%0,%1);
          else if (test_hard_reg_class (STACK_REG, src))
          else if (test_hard_reg_class (STACK_REG, src))
            return AS2 (in,%0,%1);
            return AS2 (in,%0,%1);
 
 
          return AS2 (mov,%0,%1);
          return AS2 (mov,%0,%1);
        }
        }
      else if (CONSTANT_P (src))
      else if (CONSTANT_P (src))
        {
        {
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
            return AS2 (ldi,%0,lo8(%1));
            return AS2 (ldi,%0,lo8(%1));
 
 
          if (GET_CODE (src) == CONST_INT)
          if (GET_CODE (src) == CONST_INT)
            {
            {
              if (src == const0_rtx) /* mov r,L */
              if (src == const0_rtx) /* mov r,L */
                return AS1 (clr,%0);
                return AS1 (clr,%0);
              else if (src == const1_rtx)
              else if (src == const1_rtx)
                {
                {
                  *l = 2;
                  *l = 2;
                  return (AS1 (clr,%0) CR_TAB
                  return (AS1 (clr,%0) CR_TAB
                          AS1 (inc,%0));
                          AS1 (inc,%0));
                }
                }
              else if (src == constm1_rtx)
              else if (src == constm1_rtx)
                {
                {
                  /* Immediate constants -1 to any register */
                  /* Immediate constants -1 to any register */
                  *l = 2;
                  *l = 2;
                  return (AS1 (clr,%0) CR_TAB
                  return (AS1 (clr,%0) CR_TAB
                          AS1 (dec,%0));
                          AS1 (dec,%0));
                }
                }
              else
              else
                {
                {
                  int bit_nr = exact_log2 (INTVAL (src));
                  int bit_nr = exact_log2 (INTVAL (src));
 
 
                  if (bit_nr >= 0)
                  if (bit_nr >= 0)
                    {
                    {
                      *l = 3;
                      *l = 3;
                      if (!real_l)
                      if (!real_l)
                        output_asm_insn ((AS1 (clr,%0) CR_TAB
                        output_asm_insn ((AS1 (clr,%0) CR_TAB
                                          "set"), operands);
                                          "set"), operands);
                      if (!real_l)
                      if (!real_l)
                        avr_output_bld (operands, bit_nr);
                        avr_output_bld (operands, bit_nr);
 
 
                      return "";
                      return "";
                    }
                    }
                }
                }
            }
            }
 
 
          /* Last resort, larger than loading from memory.  */
          /* Last resort, larger than loading from memory.  */
          *l = 4;
          *l = 4;
          return (AS2 (mov,__tmp_reg__,r31) CR_TAB
          return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                  AS2 (ldi,r31,lo8(%1))     CR_TAB
                  AS2 (ldi,r31,lo8(%1))     CR_TAB
                  AS2 (mov,%0,r31)          CR_TAB
                  AS2 (mov,%0,r31)          CR_TAB
                  AS2 (mov,r31,__tmp_reg__));
                  AS2 (mov,r31,__tmp_reg__));
        }
        }
      else if (GET_CODE (src) == MEM)
      else if (GET_CODE (src) == MEM)
        return out_movqi_r_mr (insn, operands, real_l); /* mov r,m */
        return out_movqi_r_mr (insn, operands, real_l); /* mov r,m */
    }
    }
  else if (GET_CODE (dest) == MEM)
  else if (GET_CODE (dest) == MEM)
    {
    {
      const char *template;
      const char *template;
 
 
      if (src == const0_rtx)
      if (src == const0_rtx)
        operands[1] = zero_reg_rtx;
        operands[1] = zero_reg_rtx;
 
 
      template = out_movqi_mr_r (insn, operands, real_l);
      template = out_movqi_mr_r (insn, operands, real_l);
 
 
      if (!real_l)
      if (!real_l)
        output_asm_insn (template, operands);
        output_asm_insn (template, operands);
 
 
      operands[1] = src;
      operands[1] = src;
    }
    }
  return "";
  return "";
}
}
 
 
 
 
const char *
const char *
output_movhi (rtx insn, rtx operands[], int *l)
output_movhi (rtx insn, rtx operands[], int *l)
{
{
  int dummy;
  int dummy;
  rtx dest = operands[0];
  rtx dest = operands[0];
  rtx src = operands[1];
  rtx src = operands[1];
  int *real_l = l;
  int *real_l = l;
 
 
  if (!l)
  if (!l)
    l = &dummy;
    l = &dummy;
 
 
  if (register_operand (dest, HImode))
  if (register_operand (dest, HImode))
    {
    {
      if (register_operand (src, HImode)) /* mov r,r */
      if (register_operand (src, HImode)) /* mov r,r */
        {
        {
          if (test_hard_reg_class (STACK_REG, dest))
          if (test_hard_reg_class (STACK_REG, dest))
            {
            {
              if (TARGET_TINY_STACK)
              if (TARGET_TINY_STACK)
                {
                {
                  *l = 1;
                  *l = 1;
                  return AS2 (out,__SP_L__,%A1);
                  return AS2 (out,__SP_L__,%A1);
                }
                }
              else if (TARGET_NO_INTERRUPTS)
              else if (TARGET_NO_INTERRUPTS)
                {
                {
                  *l = 2;
                  *l = 2;
                  return (AS2 (out,__SP_H__,%B1) CR_TAB
                  return (AS2 (out,__SP_H__,%B1) CR_TAB
                          AS2 (out,__SP_L__,%A1));
                          AS2 (out,__SP_L__,%A1));
                }
                }
 
 
              *l = 5;
              *l = 5;
              return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
              return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
                      "cli"                          CR_TAB
                      "cli"                          CR_TAB
                      AS2 (out,__SP_H__,%B1)         CR_TAB
                      AS2 (out,__SP_H__,%B1)         CR_TAB
                      AS2 (out,__SREG__,__tmp_reg__) CR_TAB
                      AS2 (out,__SREG__,__tmp_reg__) CR_TAB
                      AS2 (out,__SP_L__,%A1));
                      AS2 (out,__SP_L__,%A1));
            }
            }
          else if (test_hard_reg_class (STACK_REG, src))
          else if (test_hard_reg_class (STACK_REG, src))
            {
            {
              *l = 2;
              *l = 2;
              return (AS2 (in,%A0,__SP_L__) CR_TAB
              return (AS2 (in,%A0,__SP_L__) CR_TAB
                      AS2 (in,%B0,__SP_H__));
                      AS2 (in,%B0,__SP_H__));
            }
            }
 
 
          if (AVR_HAVE_MOVW)
          if (AVR_HAVE_MOVW)
            {
            {
              *l = 1;
              *l = 1;
              return (AS2 (movw,%0,%1));
              return (AS2 (movw,%0,%1));
            }
            }
 
 
          if (true_regnum (dest) > true_regnum (src))
          if (true_regnum (dest) > true_regnum (src))
            {
            {
              *l = 2;
              *l = 2;
              return (AS2 (mov,%B0,%B1) CR_TAB
              return (AS2 (mov,%B0,%B1) CR_TAB
                      AS2 (mov,%A0,%A1));
                      AS2 (mov,%A0,%A1));
            }
            }
          else
          else
            {
            {
              *l = 2;
              *l = 2;
              return (AS2 (mov,%A0,%A1) CR_TAB
              return (AS2 (mov,%A0,%A1) CR_TAB
                      AS2 (mov,%B0,%B1));
                      AS2 (mov,%B0,%B1));
            }
            }
        }
        }
      else if (CONSTANT_P (src))
      else if (CONSTANT_P (src))
        {
        {
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
            {
            {
              *l = 2;
              *l = 2;
              return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
              return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
                      AS2 (ldi,%B0,hi8(%1)));
                      AS2 (ldi,%B0,hi8(%1)));
            }
            }
 
 
          if (GET_CODE (src) == CONST_INT)
          if (GET_CODE (src) == CONST_INT)
            {
            {
              if (src == const0_rtx) /* mov r,L */
              if (src == const0_rtx) /* mov r,L */
                {
                {
                  *l = 2;
                  *l = 2;
                  return (AS1 (clr,%A0) CR_TAB
                  return (AS1 (clr,%A0) CR_TAB
                          AS1 (clr,%B0));
                          AS1 (clr,%B0));
                }
                }
              else if (src == const1_rtx)
              else if (src == const1_rtx)
                {
                {
                  *l = 3;
                  *l = 3;
                  return (AS1 (clr,%A0) CR_TAB
                  return (AS1 (clr,%A0) CR_TAB
                          AS1 (clr,%B0) CR_TAB
                          AS1 (clr,%B0) CR_TAB
                          AS1 (inc,%A0));
                          AS1 (inc,%A0));
                }
                }
              else if (src == constm1_rtx)
              else if (src == constm1_rtx)
                {
                {
                  /* Immediate constants -1 to any register */
                  /* Immediate constants -1 to any register */
                  *l = 3;
                  *l = 3;
                  return (AS1 (clr,%0)  CR_TAB
                  return (AS1 (clr,%0)  CR_TAB
                          AS1 (dec,%A0) CR_TAB
                          AS1 (dec,%A0) CR_TAB
                          AS2 (mov,%B0,%A0));
                          AS2 (mov,%B0,%A0));
                }
                }
              else
              else
                {
                {
                  int bit_nr = exact_log2 (INTVAL (src));
                  int bit_nr = exact_log2 (INTVAL (src));
 
 
                  if (bit_nr >= 0)
                  if (bit_nr >= 0)
                    {
                    {
                      *l = 4;
                      *l = 4;
                      if (!real_l)
                      if (!real_l)
                        output_asm_insn ((AS1 (clr,%A0) CR_TAB
                        output_asm_insn ((AS1 (clr,%A0) CR_TAB
                                          AS1 (clr,%B0) CR_TAB
                                          AS1 (clr,%B0) CR_TAB
                                          "set"), operands);
                                          "set"), operands);
                      if (!real_l)
                      if (!real_l)
                        avr_output_bld (operands, bit_nr);
                        avr_output_bld (operands, bit_nr);
 
 
                      return "";
                      return "";
                    }
                    }
                }
                }
 
 
              if ((INTVAL (src) & 0xff) == 0)
              if ((INTVAL (src) & 0xff) == 0)
                {
                {
                  *l = 5;
                  *l = 5;
                  return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                  return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                          AS1 (clr,%A0)             CR_TAB
                          AS1 (clr,%A0)             CR_TAB
                          AS2 (ldi,r31,hi8(%1))     CR_TAB
                          AS2 (ldi,r31,hi8(%1))     CR_TAB
                          AS2 (mov,%B0,r31)         CR_TAB
                          AS2 (mov,%B0,r31)         CR_TAB
                          AS2 (mov,r31,__tmp_reg__));
                          AS2 (mov,r31,__tmp_reg__));
                }
                }
              else if ((INTVAL (src) & 0xff00) == 0)
              else if ((INTVAL (src) & 0xff00) == 0)
                {
                {
                  *l = 5;
                  *l = 5;
                  return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                  return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                          AS2 (ldi,r31,lo8(%1))     CR_TAB
                          AS2 (ldi,r31,lo8(%1))     CR_TAB
                          AS2 (mov,%A0,r31)         CR_TAB
                          AS2 (mov,%A0,r31)         CR_TAB
                          AS1 (clr,%B0)             CR_TAB
                          AS1 (clr,%B0)             CR_TAB
                          AS2 (mov,r31,__tmp_reg__));
                          AS2 (mov,r31,__tmp_reg__));
                }
                }
            }
            }
 
 
          /* Last resort, equal to loading from memory.  */
          /* Last resort, equal to loading from memory.  */
          *l = 6;
          *l = 6;
          return (AS2 (mov,__tmp_reg__,r31) CR_TAB
          return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                  AS2 (ldi,r31,lo8(%1))     CR_TAB
                  AS2 (ldi,r31,lo8(%1))     CR_TAB
                  AS2 (mov,%A0,r31)         CR_TAB
                  AS2 (mov,%A0,r31)         CR_TAB
                  AS2 (ldi,r31,hi8(%1))     CR_TAB
                  AS2 (ldi,r31,hi8(%1))     CR_TAB
                  AS2 (mov,%B0,r31)         CR_TAB
                  AS2 (mov,%B0,r31)         CR_TAB
                  AS2 (mov,r31,__tmp_reg__));
                  AS2 (mov,r31,__tmp_reg__));
        }
        }
      else if (GET_CODE (src) == MEM)
      else if (GET_CODE (src) == MEM)
        return out_movhi_r_mr (insn, operands, real_l); /* mov r,m */
        return out_movhi_r_mr (insn, operands, real_l); /* mov r,m */
    }
    }
  else if (GET_CODE (dest) == MEM)
  else if (GET_CODE (dest) == MEM)
    {
    {
      const char *template;
      const char *template;
 
 
      if (src == const0_rtx)
      if (src == const0_rtx)
        operands[1] = zero_reg_rtx;
        operands[1] = zero_reg_rtx;
 
 
      template = out_movhi_mr_r (insn, operands, real_l);
      template = out_movhi_mr_r (insn, operands, real_l);
 
 
      if (!real_l)
      if (!real_l)
        output_asm_insn (template, operands);
        output_asm_insn (template, operands);
 
 
      operands[1] = src;
      operands[1] = src;
      return "";
      return "";
    }
    }
  fatal_insn ("invalid insn:", insn);
  fatal_insn ("invalid insn:", insn);
  return "";
  return "";
}
}
 
 
const char *
const char *
out_movqi_r_mr (rtx insn, rtx op[], int *l)
out_movqi_r_mr (rtx insn, rtx op[], int *l)
{
{
  rtx dest = op[0];
  rtx dest = op[0];
  rtx src = op[1];
  rtx src = op[1];
  rtx x = XEXP (src, 0);
  rtx x = XEXP (src, 0);
  int dummy;
  int dummy;
 
 
  if (!l)
  if (!l)
    l = &dummy;
    l = &dummy;
 
 
  if (CONSTANT_ADDRESS_P (x))
  if (CONSTANT_ADDRESS_P (x))
    {
    {
      if (avr_io_address_p (x, 1))
      if (avr_io_address_p (x, 1))
        {
        {
          *l = 1;
          *l = 1;
          return AS2 (in,%0,%1-0x20);
          return AS2 (in,%0,%1-0x20);
        }
        }
      *l = 2;
      *l = 2;
      return AS2 (lds,%0,%1);
      return AS2 (lds,%0,%1);
    }
    }
  /* memory access by reg+disp */
  /* memory access by reg+disp */
  else if (GET_CODE (x) == PLUS
  else if (GET_CODE (x) == PLUS
      && REG_P (XEXP (x,0))
      && REG_P (XEXP (x,0))
      && GET_CODE (XEXP (x,1)) == CONST_INT)
      && GET_CODE (XEXP (x,1)) == CONST_INT)
    {
    {
      if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (src))) >= 63)
      if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (src))) >= 63)
        {
        {
          int disp = INTVAL (XEXP (x,1));
          int disp = INTVAL (XEXP (x,1));
          if (REGNO (XEXP (x,0)) != REG_Y)
          if (REGNO (XEXP (x,0)) != REG_Y)
            fatal_insn ("incorrect insn:",insn);
            fatal_insn ("incorrect insn:",insn);
 
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
            return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
            return *l = 3, (AS2 (adiw,r28,%o1-63) CR_TAB
                            AS2 (ldd,%0,Y+63)     CR_TAB
                            AS2 (ldd,%0,Y+63)     CR_TAB
                            AS2 (sbiw,r28,%o1-63));
                            AS2 (sbiw,r28,%o1-63));
 
 
          return *l = 5, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
          return *l = 5, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o1)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o1)) CR_TAB
                          AS2 (ld,%0,Y)            CR_TAB
                          AS2 (ld,%0,Y)            CR_TAB
                          AS2 (subi,r28,lo8(%o1))  CR_TAB
                          AS2 (subi,r28,lo8(%o1))  CR_TAB
                          AS2 (sbci,r29,hi8(%o1)));
                          AS2 (sbci,r29,hi8(%o1)));
        }
        }
      else if (REGNO (XEXP (x,0)) == REG_X)
      else if (REGNO (XEXP (x,0)) == REG_X)
        {
        {
          /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
          /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude
             it but I have this situation with extremal optimizing options.  */
             it but I have this situation with extremal optimizing options.  */
          if (reg_overlap_mentioned_p (dest, XEXP (x,0))
          if (reg_overlap_mentioned_p (dest, XEXP (x,0))
              || reg_unused_after (insn, XEXP (x,0)))
              || reg_unused_after (insn, XEXP (x,0)))
            return *l = 2, (AS2 (adiw,r26,%o1) CR_TAB
            return *l = 2, (AS2 (adiw,r26,%o1) CR_TAB
                            AS2 (ld,%0,X));
                            AS2 (ld,%0,X));
 
 
          return *l = 3, (AS2 (adiw,r26,%o1) CR_TAB
          return *l = 3, (AS2 (adiw,r26,%o1) CR_TAB
                          AS2 (ld,%0,X)      CR_TAB
                          AS2 (ld,%0,X)      CR_TAB
                          AS2 (sbiw,r26,%o1));
                          AS2 (sbiw,r26,%o1));
        }
        }
      *l = 1;
      *l = 1;
      return AS2 (ldd,%0,%1);
      return AS2 (ldd,%0,%1);
    }
    }
  *l = 1;
  *l = 1;
  return AS2 (ld,%0,%1);
  return AS2 (ld,%0,%1);
}
}
 
 
const char *
const char *
out_movhi_r_mr (rtx insn, rtx op[], int *l)
out_movhi_r_mr (rtx insn, rtx op[], int *l)
{
{
  rtx dest = op[0];
  rtx dest = op[0];
  rtx src = op[1];
  rtx src = op[1];
  rtx base = XEXP (src, 0);
  rtx base = XEXP (src, 0);
  int reg_dest = true_regnum (dest);
  int reg_dest = true_regnum (dest);
  int reg_base = true_regnum (base);
  int reg_base = true_regnum (base);
  /* "volatile" forces reading low byte first, even if less efficient,
  /* "volatile" forces reading low byte first, even if less efficient,
     for correct operation with 16-bit I/O registers.  */
     for correct operation with 16-bit I/O registers.  */
  int mem_volatile_p = MEM_VOLATILE_P (src);
  int mem_volatile_p = MEM_VOLATILE_P (src);
  int tmp;
  int tmp;
 
 
  if (!l)
  if (!l)
    l = &tmp;
    l = &tmp;
 
 
  if (reg_base > 0)
  if (reg_base > 0)
    {
    {
      if (reg_dest == reg_base)         /* R = (R) */
      if (reg_dest == reg_base)         /* R = (R) */
        {
        {
          *l = 3;
          *l = 3;
          return (AS2 (ld,__tmp_reg__,%1+) CR_TAB
          return (AS2 (ld,__tmp_reg__,%1+) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (mov,%A0,__tmp_reg__));
                  AS2 (mov,%A0,__tmp_reg__));
        }
        }
      else if (reg_base == REG_X)        /* (R26) */
      else if (reg_base == REG_X)        /* (R26) */
        {
        {
          if (reg_unused_after (insn, base))
          if (reg_unused_after (insn, base))
            {
            {
              *l = 2;
              *l = 2;
              return (AS2 (ld,%A0,X+) CR_TAB
              return (AS2 (ld,%A0,X+) CR_TAB
                      AS2 (ld,%B0,X));
                      AS2 (ld,%B0,X));
            }
            }
          *l  = 3;
          *l  = 3;
          return (AS2 (ld,%A0,X+) CR_TAB
          return (AS2 (ld,%A0,X+) CR_TAB
                  AS2 (ld,%B0,X) CR_TAB
                  AS2 (ld,%B0,X) CR_TAB
                  AS2 (sbiw,r26,1));
                  AS2 (sbiw,r26,1));
        }
        }
      else                      /* (R)  */
      else                      /* (R)  */
        {
        {
          *l = 2;
          *l = 2;
          return (AS2 (ld,%A0,%1)    CR_TAB
          return (AS2 (ld,%A0,%1)    CR_TAB
                  AS2 (ldd,%B0,%1+1));
                  AS2 (ldd,%B0,%1+1));
        }
        }
    }
    }
  else if (GET_CODE (base) == PLUS) /* (R + i) */
  else if (GET_CODE (base) == PLUS) /* (R + i) */
    {
    {
      int disp = INTVAL (XEXP (base, 1));
      int disp = INTVAL (XEXP (base, 1));
      int reg_base = true_regnum (XEXP (base, 0));
      int reg_base = true_regnum (XEXP (base, 0));
 
 
      if (disp > MAX_LD_OFFSET (GET_MODE (src)))
      if (disp > MAX_LD_OFFSET (GET_MODE (src)))
        {
        {
          if (REGNO (XEXP (base, 0)) != REG_Y)
          if (REGNO (XEXP (base, 0)) != REG_Y)
            fatal_insn ("incorrect insn:",insn);
            fatal_insn ("incorrect insn:",insn);
 
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
            return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
            return *l = 4, (AS2 (adiw,r28,%o1-62) CR_TAB
                            AS2 (ldd,%A0,Y+62)    CR_TAB
                            AS2 (ldd,%A0,Y+62)    CR_TAB
                            AS2 (ldd,%B0,Y+63)    CR_TAB
                            AS2 (ldd,%B0,Y+63)    CR_TAB
                            AS2 (sbiw,r28,%o1-62));
                            AS2 (sbiw,r28,%o1-62));
 
 
          return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
          return *l = 6, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o1)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o1)) CR_TAB
                          AS2 (ld,%A0,Y)           CR_TAB
                          AS2 (ld,%A0,Y)           CR_TAB
                          AS2 (ldd,%B0,Y+1)        CR_TAB
                          AS2 (ldd,%B0,Y+1)        CR_TAB
                          AS2 (subi,r28,lo8(%o1))  CR_TAB
                          AS2 (subi,r28,lo8(%o1))  CR_TAB
                          AS2 (sbci,r29,hi8(%o1)));
                          AS2 (sbci,r29,hi8(%o1)));
        }
        }
      if (reg_base == REG_X)
      if (reg_base == REG_X)
        {
        {
          /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
          /* This is a paranoid case. LEGITIMIZE_RELOAD_ADDRESS must exclude
             it but I have this situation with extremal
             it but I have this situation with extremal
             optimization options.  */
             optimization options.  */
 
 
          *l = 4;
          *l = 4;
          if (reg_base == reg_dest)
          if (reg_base == reg_dest)
            return (AS2 (adiw,r26,%o1)      CR_TAB
            return (AS2 (adiw,r26,%o1)      CR_TAB
                    AS2 (ld,__tmp_reg__,X+) CR_TAB
                    AS2 (ld,__tmp_reg__,X+) CR_TAB
                    AS2 (ld,%B0,X)          CR_TAB
                    AS2 (ld,%B0,X)          CR_TAB
                    AS2 (mov,%A0,__tmp_reg__));
                    AS2 (mov,%A0,__tmp_reg__));
 
 
          return (AS2 (adiw,r26,%o1) CR_TAB
          return (AS2 (adiw,r26,%o1) CR_TAB
                  AS2 (ld,%A0,X+)    CR_TAB
                  AS2 (ld,%A0,X+)    CR_TAB
                  AS2 (ld,%B0,X)     CR_TAB
                  AS2 (ld,%B0,X)     CR_TAB
                  AS2 (sbiw,r26,%o1+1));
                  AS2 (sbiw,r26,%o1+1));
        }
        }
 
 
      if (reg_base == reg_dest)
      if (reg_base == reg_dest)
        {
        {
          *l = 3;
          *l = 3;
          return (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
          return (AS2 (ldd,__tmp_reg__,%A1) CR_TAB
                  AS2 (ldd,%B0,%B1)         CR_TAB
                  AS2 (ldd,%B0,%B1)         CR_TAB
                  AS2 (mov,%A0,__tmp_reg__));
                  AS2 (mov,%A0,__tmp_reg__));
        }
        }
 
 
      *l = 2;
      *l = 2;
      return (AS2 (ldd,%A0,%A1) CR_TAB
      return (AS2 (ldd,%A0,%A1) CR_TAB
              AS2 (ldd,%B0,%B1));
              AS2 (ldd,%B0,%B1));
    }
    }
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
    {
    {
      if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
      if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
        fatal_insn ("incorrect insn:", insn);
        fatal_insn ("incorrect insn:", insn);
 
 
      if (mem_volatile_p)
      if (mem_volatile_p)
        {
        {
          if (REGNO (XEXP (base, 0)) == REG_X)
          if (REGNO (XEXP (base, 0)) == REG_X)
            {
            {
              *l = 4;
              *l = 4;
              return (AS2 (sbiw,r26,2)  CR_TAB
              return (AS2 (sbiw,r26,2)  CR_TAB
                      AS2 (ld,%A0,X+)   CR_TAB
                      AS2 (ld,%A0,X+)   CR_TAB
                      AS2 (ld,%B0,X)    CR_TAB
                      AS2 (ld,%B0,X)    CR_TAB
                      AS2 (sbiw,r26,1));
                      AS2 (sbiw,r26,1));
            }
            }
          else
          else
            {
            {
              *l = 3;
              *l = 3;
              return (AS2 (sbiw,%r1,2)   CR_TAB
              return (AS2 (sbiw,%r1,2)   CR_TAB
                      AS2 (ld,%A0,%p1)  CR_TAB
                      AS2 (ld,%A0,%p1)  CR_TAB
                      AS2 (ldd,%B0,%p1+1));
                      AS2 (ldd,%B0,%p1+1));
            }
            }
        }
        }
 
 
      *l = 2;
      *l = 2;
      return (AS2 (ld,%B0,%1) CR_TAB
      return (AS2 (ld,%B0,%1) CR_TAB
              AS2 (ld,%A0,%1));
              AS2 (ld,%A0,%1));
    }
    }
  else if (GET_CODE (base) == POST_INC) /* (R++) */
  else if (GET_CODE (base) == POST_INC) /* (R++) */
    {
    {
      if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
      if (reg_overlap_mentioned_p (dest, XEXP (base, 0)))
        fatal_insn ("incorrect insn:", insn);
        fatal_insn ("incorrect insn:", insn);
 
 
      *l = 2;
      *l = 2;
      return (AS2 (ld,%A0,%1)  CR_TAB
      return (AS2 (ld,%A0,%1)  CR_TAB
              AS2 (ld,%B0,%1));
              AS2 (ld,%B0,%1));
    }
    }
  else if (CONSTANT_ADDRESS_P (base))
  else if (CONSTANT_ADDRESS_P (base))
    {
    {
      if (avr_io_address_p (base, 2))
      if (avr_io_address_p (base, 2))
        {
        {
          *l = 2;
          *l = 2;
          return (AS2 (in,%A0,%A1-0x20) CR_TAB
          return (AS2 (in,%A0,%A1-0x20) CR_TAB
                  AS2 (in,%B0,%B1-0x20));
                  AS2 (in,%B0,%B1-0x20));
        }
        }
      *l = 4;
      *l = 4;
      return (AS2 (lds,%A0,%A1) CR_TAB
      return (AS2 (lds,%A0,%A1) CR_TAB
              AS2 (lds,%B0,%B1));
              AS2 (lds,%B0,%B1));
    }
    }
 
 
  fatal_insn ("unknown move insn:",insn);
  fatal_insn ("unknown move insn:",insn);
  return "";
  return "";
}
}
 
 
const char *
const char *
out_movsi_r_mr (rtx insn, rtx op[], int *l)
out_movsi_r_mr (rtx insn, rtx op[], int *l)
{
{
  rtx dest = op[0];
  rtx dest = op[0];
  rtx src = op[1];
  rtx src = op[1];
  rtx base = XEXP (src, 0);
  rtx base = XEXP (src, 0);
  int reg_dest = true_regnum (dest);
  int reg_dest = true_regnum (dest);
  int reg_base = true_regnum (base);
  int reg_base = true_regnum (base);
  int tmp;
  int tmp;
 
 
  if (!l)
  if (!l)
    l = &tmp;
    l = &tmp;
 
 
  if (reg_base > 0)
  if (reg_base > 0)
    {
    {
      if (reg_base == REG_X)        /* (R26) */
      if (reg_base == REG_X)        /* (R26) */
        {
        {
          if (reg_dest == REG_X)
          if (reg_dest == REG_X)
            /* "ld r26,-X" is undefined */
            /* "ld r26,-X" is undefined */
            return *l=7, (AS2 (adiw,r26,3)        CR_TAB
            return *l=7, (AS2 (adiw,r26,3)        CR_TAB
                          AS2 (ld,r29,X)          CR_TAB
                          AS2 (ld,r29,X)          CR_TAB
                          AS2 (ld,r28,-X)         CR_TAB
                          AS2 (ld,r28,-X)         CR_TAB
                          AS2 (ld,__tmp_reg__,-X) CR_TAB
                          AS2 (ld,__tmp_reg__,-X) CR_TAB
                          AS2 (sbiw,r26,1)        CR_TAB
                          AS2 (sbiw,r26,1)        CR_TAB
                          AS2 (ld,r26,X)          CR_TAB
                          AS2 (ld,r26,X)          CR_TAB
                          AS2 (mov,r27,__tmp_reg__));
                          AS2 (mov,r27,__tmp_reg__));
          else if (reg_dest == REG_X - 2)
          else if (reg_dest == REG_X - 2)
            return *l=5, (AS2 (ld,%A0,X+)  CR_TAB
            return *l=5, (AS2 (ld,%A0,X+)  CR_TAB
                          AS2 (ld,%B0,X+) CR_TAB
                          AS2 (ld,%B0,X+) CR_TAB
                          AS2 (ld,__tmp_reg__,X+)  CR_TAB
                          AS2 (ld,__tmp_reg__,X+)  CR_TAB
                          AS2 (ld,%D0,X)  CR_TAB
                          AS2 (ld,%D0,X)  CR_TAB
                          AS2 (mov,%C0,__tmp_reg__));
                          AS2 (mov,%C0,__tmp_reg__));
          else if (reg_unused_after (insn, base))
          else if (reg_unused_after (insn, base))
            return  *l=4, (AS2 (ld,%A0,X+)  CR_TAB
            return  *l=4, (AS2 (ld,%A0,X+)  CR_TAB
                           AS2 (ld,%B0,X+) CR_TAB
                           AS2 (ld,%B0,X+) CR_TAB
                           AS2 (ld,%C0,X+) CR_TAB
                           AS2 (ld,%C0,X+) CR_TAB
                           AS2 (ld,%D0,X));
                           AS2 (ld,%D0,X));
          else
          else
            return  *l=5, (AS2 (ld,%A0,X+)  CR_TAB
            return  *l=5, (AS2 (ld,%A0,X+)  CR_TAB
                           AS2 (ld,%B0,X+) CR_TAB
                           AS2 (ld,%B0,X+) CR_TAB
                           AS2 (ld,%C0,X+) CR_TAB
                           AS2 (ld,%C0,X+) CR_TAB
                           AS2 (ld,%D0,X)  CR_TAB
                           AS2 (ld,%D0,X)  CR_TAB
                           AS2 (sbiw,r26,3));
                           AS2 (sbiw,r26,3));
        }
        }
      else
      else
        {
        {
          if (reg_dest == reg_base)
          if (reg_dest == reg_base)
            return *l=5, (AS2 (ldd,%D0,%1+3) CR_TAB
            return *l=5, (AS2 (ldd,%D0,%1+3) CR_TAB
                          AS2 (ldd,%C0,%1+2) CR_TAB
                          AS2 (ldd,%C0,%1+2) CR_TAB
                          AS2 (ldd,__tmp_reg__,%1+1)  CR_TAB
                          AS2 (ldd,__tmp_reg__,%1+1)  CR_TAB
                          AS2 (ld,%A0,%1)  CR_TAB
                          AS2 (ld,%A0,%1)  CR_TAB
                          AS2 (mov,%B0,__tmp_reg__));
                          AS2 (mov,%B0,__tmp_reg__));
          else if (reg_base == reg_dest + 2)
          else if (reg_base == reg_dest + 2)
            return *l=5, (AS2 (ld ,%A0,%1)    CR_TAB
            return *l=5, (AS2 (ld ,%A0,%1)    CR_TAB
                          AS2 (ldd,%B0,%1+1) CR_TAB
                          AS2 (ldd,%B0,%1+1) CR_TAB
                          AS2 (ldd,__tmp_reg__,%1+2)  CR_TAB
                          AS2 (ldd,__tmp_reg__,%1+2)  CR_TAB
                          AS2 (ldd,%D0,%1+3) CR_TAB
                          AS2 (ldd,%D0,%1+3) CR_TAB
                          AS2 (mov,%C0,__tmp_reg__));
                          AS2 (mov,%C0,__tmp_reg__));
          else
          else
            return *l=4, (AS2 (ld ,%A0,%1)   CR_TAB
            return *l=4, (AS2 (ld ,%A0,%1)   CR_TAB
                          AS2 (ldd,%B0,%1+1) CR_TAB
                          AS2 (ldd,%B0,%1+1) CR_TAB
                          AS2 (ldd,%C0,%1+2) CR_TAB
                          AS2 (ldd,%C0,%1+2) CR_TAB
                          AS2 (ldd,%D0,%1+3));
                          AS2 (ldd,%D0,%1+3));
        }
        }
    }
    }
  else if (GET_CODE (base) == PLUS) /* (R + i) */
  else if (GET_CODE (base) == PLUS) /* (R + i) */
    {
    {
      int disp = INTVAL (XEXP (base, 1));
      int disp = INTVAL (XEXP (base, 1));
 
 
      if (disp > MAX_LD_OFFSET (GET_MODE (src)))
      if (disp > MAX_LD_OFFSET (GET_MODE (src)))
        {
        {
          if (REGNO (XEXP (base, 0)) != REG_Y)
          if (REGNO (XEXP (base, 0)) != REG_Y)
            fatal_insn ("incorrect insn:",insn);
            fatal_insn ("incorrect insn:",insn);
 
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (src)))
            return *l = 6, (AS2 (adiw,r28,%o1-60) CR_TAB
            return *l = 6, (AS2 (adiw,r28,%o1-60) CR_TAB
                            AS2 (ldd,%A0,Y+60)    CR_TAB
                            AS2 (ldd,%A0,Y+60)    CR_TAB
                            AS2 (ldd,%B0,Y+61)    CR_TAB
                            AS2 (ldd,%B0,Y+61)    CR_TAB
                            AS2 (ldd,%C0,Y+62)    CR_TAB
                            AS2 (ldd,%C0,Y+62)    CR_TAB
                            AS2 (ldd,%D0,Y+63)    CR_TAB
                            AS2 (ldd,%D0,Y+63)    CR_TAB
                            AS2 (sbiw,r28,%o1-60));
                            AS2 (sbiw,r28,%o1-60));
 
 
          return *l = 8, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
          return *l = 8, (AS2 (subi,r28,lo8(-%o1)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o1)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o1)) CR_TAB
                          AS2 (ld,%A0,Y)           CR_TAB
                          AS2 (ld,%A0,Y)           CR_TAB
                          AS2 (ldd,%B0,Y+1)        CR_TAB
                          AS2 (ldd,%B0,Y+1)        CR_TAB
                          AS2 (ldd,%C0,Y+2)        CR_TAB
                          AS2 (ldd,%C0,Y+2)        CR_TAB
                          AS2 (ldd,%D0,Y+3)        CR_TAB
                          AS2 (ldd,%D0,Y+3)        CR_TAB
                          AS2 (subi,r28,lo8(%o1))  CR_TAB
                          AS2 (subi,r28,lo8(%o1))  CR_TAB
                          AS2 (sbci,r29,hi8(%o1)));
                          AS2 (sbci,r29,hi8(%o1)));
        }
        }
 
 
      reg_base = true_regnum (XEXP (base, 0));
      reg_base = true_regnum (XEXP (base, 0));
      if (reg_base == REG_X)
      if (reg_base == REG_X)
        {
        {
          /* R = (X + d) */
          /* R = (X + d) */
          if (reg_dest == REG_X)
          if (reg_dest == REG_X)
            {
            {
              *l = 7;
              *l = 7;
              /* "ld r26,-X" is undefined */
              /* "ld r26,-X" is undefined */
              return (AS2 (adiw,r26,%o1+3)    CR_TAB
              return (AS2 (adiw,r26,%o1+3)    CR_TAB
                      AS2 (ld,r29,X)          CR_TAB
                      AS2 (ld,r29,X)          CR_TAB
                      AS2 (ld,r28,-X)         CR_TAB
                      AS2 (ld,r28,-X)         CR_TAB
                      AS2 (ld,__tmp_reg__,-X) CR_TAB
                      AS2 (ld,__tmp_reg__,-X) CR_TAB
                      AS2 (sbiw,r26,1)        CR_TAB
                      AS2 (sbiw,r26,1)        CR_TAB
                      AS2 (ld,r26,X)          CR_TAB
                      AS2 (ld,r26,X)          CR_TAB
                      AS2 (mov,r27,__tmp_reg__));
                      AS2 (mov,r27,__tmp_reg__));
            }
            }
          *l = 6;
          *l = 6;
          if (reg_dest == REG_X - 2)
          if (reg_dest == REG_X - 2)
            return (AS2 (adiw,r26,%o1)      CR_TAB
            return (AS2 (adiw,r26,%o1)      CR_TAB
                    AS2 (ld,r24,X+)         CR_TAB
                    AS2 (ld,r24,X+)         CR_TAB
                    AS2 (ld,r25,X+)         CR_TAB
                    AS2 (ld,r25,X+)         CR_TAB
                    AS2 (ld,__tmp_reg__,X+) CR_TAB
                    AS2 (ld,__tmp_reg__,X+) CR_TAB
                    AS2 (ld,r27,X)          CR_TAB
                    AS2 (ld,r27,X)          CR_TAB
                    AS2 (mov,r26,__tmp_reg__));
                    AS2 (mov,r26,__tmp_reg__));
 
 
          return (AS2 (adiw,r26,%o1) CR_TAB
          return (AS2 (adiw,r26,%o1) CR_TAB
                  AS2 (ld,%A0,X+)    CR_TAB
                  AS2 (ld,%A0,X+)    CR_TAB
                  AS2 (ld,%B0,X+)    CR_TAB
                  AS2 (ld,%B0,X+)    CR_TAB
                  AS2 (ld,%C0,X+)    CR_TAB
                  AS2 (ld,%C0,X+)    CR_TAB
                  AS2 (ld,%D0,X)     CR_TAB
                  AS2 (ld,%D0,X)     CR_TAB
                  AS2 (sbiw,r26,%o1+3));
                  AS2 (sbiw,r26,%o1+3));
        }
        }
      if (reg_dest == reg_base)
      if (reg_dest == reg_base)
        return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
        return *l=5, (AS2 (ldd,%D0,%D1) CR_TAB
                      AS2 (ldd,%C0,%C1) CR_TAB
                      AS2 (ldd,%C0,%C1) CR_TAB
                      AS2 (ldd,__tmp_reg__,%B1)  CR_TAB
                      AS2 (ldd,__tmp_reg__,%B1)  CR_TAB
                      AS2 (ldd,%A0,%A1) CR_TAB
                      AS2 (ldd,%A0,%A1) CR_TAB
                      AS2 (mov,%B0,__tmp_reg__));
                      AS2 (mov,%B0,__tmp_reg__));
      else if (reg_dest == reg_base - 2)
      else if (reg_dest == reg_base - 2)
        return *l=5, (AS2 (ldd,%A0,%A1) CR_TAB
        return *l=5, (AS2 (ldd,%A0,%A1) CR_TAB
                      AS2 (ldd,%B0,%B1) CR_TAB
                      AS2 (ldd,%B0,%B1) CR_TAB
                      AS2 (ldd,__tmp_reg__,%C1)  CR_TAB
                      AS2 (ldd,__tmp_reg__,%C1)  CR_TAB
                      AS2 (ldd,%D0,%D1) CR_TAB
                      AS2 (ldd,%D0,%D1) CR_TAB
                      AS2 (mov,%C0,__tmp_reg__));
                      AS2 (mov,%C0,__tmp_reg__));
      return *l=4, (AS2 (ldd,%A0,%A1) CR_TAB
      return *l=4, (AS2 (ldd,%A0,%A1) CR_TAB
                    AS2 (ldd,%B0,%B1) CR_TAB
                    AS2 (ldd,%B0,%B1) CR_TAB
                    AS2 (ldd,%C0,%C1) CR_TAB
                    AS2 (ldd,%C0,%C1) CR_TAB
                    AS2 (ldd,%D0,%D1));
                    AS2 (ldd,%D0,%D1));
    }
    }
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
    return *l=4, (AS2 (ld,%D0,%1) CR_TAB
    return *l=4, (AS2 (ld,%D0,%1) CR_TAB
                  AS2 (ld,%C0,%1) CR_TAB
                  AS2 (ld,%C0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%A0,%1));
                  AS2 (ld,%A0,%1));
  else if (GET_CODE (base) == POST_INC) /* (R++) */
  else if (GET_CODE (base) == POST_INC) /* (R++) */
    return *l=4, (AS2 (ld,%A0,%1) CR_TAB
    return *l=4, (AS2 (ld,%A0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%B0,%1) CR_TAB
                  AS2 (ld,%C0,%1) CR_TAB
                  AS2 (ld,%C0,%1) CR_TAB
                  AS2 (ld,%D0,%1));
                  AS2 (ld,%D0,%1));
  else if (CONSTANT_ADDRESS_P (base))
  else if (CONSTANT_ADDRESS_P (base))
      return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
      return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
                    AS2 (lds,%B0,%B1) CR_TAB
                    AS2 (lds,%B0,%B1) CR_TAB
                    AS2 (lds,%C0,%C1) CR_TAB
                    AS2 (lds,%C0,%C1) CR_TAB
                    AS2 (lds,%D0,%D1));
                    AS2 (lds,%D0,%D1));
 
 
  fatal_insn ("unknown move insn:",insn);
  fatal_insn ("unknown move insn:",insn);
  return "";
  return "";
}
}
 
 
const char *
const char *
out_movsi_mr_r (rtx insn, rtx op[], int *l)
out_movsi_mr_r (rtx insn, rtx op[], int *l)
{
{
  rtx dest = op[0];
  rtx dest = op[0];
  rtx src = op[1];
  rtx src = op[1];
  rtx base = XEXP (dest, 0);
  rtx base = XEXP (dest, 0);
  int reg_base = true_regnum (base);
  int reg_base = true_regnum (base);
  int reg_src = true_regnum (src);
  int reg_src = true_regnum (src);
  int tmp;
  int tmp;
 
 
  if (!l)
  if (!l)
    l = &tmp;
    l = &tmp;
 
 
  if (CONSTANT_ADDRESS_P (base))
  if (CONSTANT_ADDRESS_P (base))
    return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
    return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
                 AS2 (sts,%B0,%B1) CR_TAB
                 AS2 (sts,%B0,%B1) CR_TAB
                 AS2 (sts,%C0,%C1) CR_TAB
                 AS2 (sts,%C0,%C1) CR_TAB
                 AS2 (sts,%D0,%D1));
                 AS2 (sts,%D0,%D1));
  if (reg_base > 0)                 /* (r) */
  if (reg_base > 0)                 /* (r) */
    {
    {
      if (reg_base == REG_X)                /* (R26) */
      if (reg_base == REG_X)                /* (R26) */
        {
        {
          if (reg_src == REG_X)
          if (reg_src == REG_X)
            {
            {
              /* "st X+,r26" is undefined */
              /* "st X+,r26" is undefined */
              if (reg_unused_after (insn, base))
              if (reg_unused_after (insn, base))
                return *l=6, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                return *l=6, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                              AS2 (st,X,r26)            CR_TAB
                              AS2 (st,X,r26)            CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (st,X+,__tmp_reg__)   CR_TAB
                              AS2 (st,X+,__tmp_reg__)   CR_TAB
                              AS2 (st,X+,r28)           CR_TAB
                              AS2 (st,X+,r28)           CR_TAB
                              AS2 (st,X,r29));
                              AS2 (st,X,r29));
              else
              else
                return *l=7, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                return *l=7, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                              AS2 (st,X,r26)            CR_TAB
                              AS2 (st,X,r26)            CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (st,X+,__tmp_reg__)   CR_TAB
                              AS2 (st,X+,__tmp_reg__)   CR_TAB
                              AS2 (st,X+,r28)           CR_TAB
                              AS2 (st,X+,r28)           CR_TAB
                              AS2 (st,X,r29)            CR_TAB
                              AS2 (st,X,r29)            CR_TAB
                              AS2 (sbiw,r26,3));
                              AS2 (sbiw,r26,3));
            }
            }
          else if (reg_base == reg_src + 2)
          else if (reg_base == reg_src + 2)
            {
            {
              if (reg_unused_after (insn, base))
              if (reg_unused_after (insn, base))
                return *l=7, (AS2 (mov,__zero_reg__,%C1) CR_TAB
                return *l=7, (AS2 (mov,__zero_reg__,%C1) CR_TAB
                              AS2 (mov,__tmp_reg__,%D1) CR_TAB
                              AS2 (mov,__tmp_reg__,%D1) CR_TAB
                              AS2 (st,%0+,%A1) CR_TAB
                              AS2 (st,%0+,%A1) CR_TAB
                              AS2 (st,%0+,%B1) CR_TAB
                              AS2 (st,%0+,%B1) CR_TAB
                              AS2 (st,%0+,__zero_reg__)  CR_TAB
                              AS2 (st,%0+,__zero_reg__)  CR_TAB
                              AS2 (st,%0,__tmp_reg__)   CR_TAB
                              AS2 (st,%0,__tmp_reg__)   CR_TAB
                              AS1 (clr,__zero_reg__));
                              AS1 (clr,__zero_reg__));
              else
              else
                return *l=8, (AS2 (mov,__zero_reg__,%C1) CR_TAB
                return *l=8, (AS2 (mov,__zero_reg__,%C1) CR_TAB
                              AS2 (mov,__tmp_reg__,%D1) CR_TAB
                              AS2 (mov,__tmp_reg__,%D1) CR_TAB
                              AS2 (st,%0+,%A1) CR_TAB
                              AS2 (st,%0+,%A1) CR_TAB
                              AS2 (st,%0+,%B1) CR_TAB
                              AS2 (st,%0+,%B1) CR_TAB
                              AS2 (st,%0+,__zero_reg__)  CR_TAB
                              AS2 (st,%0+,__zero_reg__)  CR_TAB
                              AS2 (st,%0,__tmp_reg__)   CR_TAB
                              AS2 (st,%0,__tmp_reg__)   CR_TAB
                              AS1 (clr,__zero_reg__)     CR_TAB
                              AS1 (clr,__zero_reg__)     CR_TAB
                              AS2 (sbiw,r26,3));
                              AS2 (sbiw,r26,3));
            }
            }
          return *l=5, (AS2 (st,%0+,%A1)  CR_TAB
          return *l=5, (AS2 (st,%0+,%A1)  CR_TAB
                        AS2 (st,%0+,%B1) CR_TAB
                        AS2 (st,%0+,%B1) CR_TAB
                        AS2 (st,%0+,%C1) CR_TAB
                        AS2 (st,%0+,%C1) CR_TAB
                        AS2 (st,%0,%D1)  CR_TAB
                        AS2 (st,%0,%D1)  CR_TAB
                        AS2 (sbiw,r26,3));
                        AS2 (sbiw,r26,3));
        }
        }
      else
      else
        return *l=4, (AS2 (st,%0,%A1)    CR_TAB
        return *l=4, (AS2 (st,%0,%A1)    CR_TAB
                      AS2 (std,%0+1,%B1) CR_TAB
                      AS2 (std,%0+1,%B1) CR_TAB
                      AS2 (std,%0+2,%C1) CR_TAB
                      AS2 (std,%0+2,%C1) CR_TAB
                      AS2 (std,%0+3,%D1));
                      AS2 (std,%0+3,%D1));
    }
    }
  else if (GET_CODE (base) == PLUS) /* (R + i) */
  else if (GET_CODE (base) == PLUS) /* (R + i) */
    {
    {
      int disp = INTVAL (XEXP (base, 1));
      int disp = INTVAL (XEXP (base, 1));
      reg_base = REGNO (XEXP (base, 0));
      reg_base = REGNO (XEXP (base, 0));
      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
        {
        {
          if (reg_base != REG_Y)
          if (reg_base != REG_Y)
            fatal_insn ("incorrect insn:",insn);
            fatal_insn ("incorrect insn:",insn);
 
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
            return *l = 6, (AS2 (adiw,r28,%o0-60) CR_TAB
            return *l = 6, (AS2 (adiw,r28,%o0-60) CR_TAB
                            AS2 (std,Y+60,%A1)    CR_TAB
                            AS2 (std,Y+60,%A1)    CR_TAB
                            AS2 (std,Y+61,%B1)    CR_TAB
                            AS2 (std,Y+61,%B1)    CR_TAB
                            AS2 (std,Y+62,%C1)    CR_TAB
                            AS2 (std,Y+62,%C1)    CR_TAB
                            AS2 (std,Y+63,%D1)    CR_TAB
                            AS2 (std,Y+63,%D1)    CR_TAB
                            AS2 (sbiw,r28,%o0-60));
                            AS2 (sbiw,r28,%o0-60));
 
 
          return *l = 8, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
          return *l = 8, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o0)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o0)) CR_TAB
                          AS2 (st,Y,%A1)           CR_TAB
                          AS2 (st,Y,%A1)           CR_TAB
                          AS2 (std,Y+1,%B1)        CR_TAB
                          AS2 (std,Y+1,%B1)        CR_TAB
                          AS2 (std,Y+2,%C1)        CR_TAB
                          AS2 (std,Y+2,%C1)        CR_TAB
                          AS2 (std,Y+3,%D1)        CR_TAB
                          AS2 (std,Y+3,%D1)        CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (sbci,r29,hi8(%o0)));
                          AS2 (sbci,r29,hi8(%o0)));
        }
        }
      if (reg_base == REG_X)
      if (reg_base == REG_X)
        {
        {
          /* (X + d) = R */
          /* (X + d) = R */
          if (reg_src == REG_X)
          if (reg_src == REG_X)
            {
            {
              *l = 9;
              *l = 9;
              return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
              return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
                      AS2 (mov,__zero_reg__,r27) CR_TAB
                      AS2 (mov,__zero_reg__,r27) CR_TAB
                      AS2 (adiw,r26,%o0)         CR_TAB
                      AS2 (adiw,r26,%o0)         CR_TAB
                      AS2 (st,X+,__tmp_reg__)    CR_TAB
                      AS2 (st,X+,__tmp_reg__)    CR_TAB
                      AS2 (st,X+,__zero_reg__)   CR_TAB
                      AS2 (st,X+,__zero_reg__)   CR_TAB
                      AS2 (st,X+,r28)            CR_TAB
                      AS2 (st,X+,r28)            CR_TAB
                      AS2 (st,X,r29)             CR_TAB
                      AS2 (st,X,r29)             CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
                      AS2 (sbiw,r26,%o0+3));
                      AS2 (sbiw,r26,%o0+3));
            }
            }
          else if (reg_src == REG_X - 2)
          else if (reg_src == REG_X - 2)
            {
            {
              *l = 9;
              *l = 9;
              return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
              return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
                      AS2 (mov,__zero_reg__,r27) CR_TAB
                      AS2 (mov,__zero_reg__,r27) CR_TAB
                      AS2 (adiw,r26,%o0)         CR_TAB
                      AS2 (adiw,r26,%o0)         CR_TAB
                      AS2 (st,X+,r24)            CR_TAB
                      AS2 (st,X+,r24)            CR_TAB
                      AS2 (st,X+,r25)            CR_TAB
                      AS2 (st,X+,r25)            CR_TAB
                      AS2 (st,X+,__tmp_reg__)    CR_TAB
                      AS2 (st,X+,__tmp_reg__)    CR_TAB
                      AS2 (st,X,__zero_reg__)    CR_TAB
                      AS2 (st,X,__zero_reg__)    CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
                      AS2 (sbiw,r26,%o0+3));
                      AS2 (sbiw,r26,%o0+3));
            }
            }
          *l = 6;
          *l = 6;
          return (AS2 (adiw,r26,%o0) CR_TAB
          return (AS2 (adiw,r26,%o0) CR_TAB
                  AS2 (st,X+,%A1)    CR_TAB
                  AS2 (st,X+,%A1)    CR_TAB
                  AS2 (st,X+,%B1)    CR_TAB
                  AS2 (st,X+,%B1)    CR_TAB
                  AS2 (st,X+,%C1)    CR_TAB
                  AS2 (st,X+,%C1)    CR_TAB
                  AS2 (st,X,%D1)     CR_TAB
                  AS2 (st,X,%D1)     CR_TAB
                  AS2 (sbiw,r26,%o0+3));
                  AS2 (sbiw,r26,%o0+3));
        }
        }
      return *l=4, (AS2 (std,%A0,%A1)    CR_TAB
      return *l=4, (AS2 (std,%A0,%A1)    CR_TAB
                    AS2 (std,%B0,%B1) CR_TAB
                    AS2 (std,%B0,%B1) CR_TAB
                    AS2 (std,%C0,%C1) CR_TAB
                    AS2 (std,%C0,%C1) CR_TAB
                    AS2 (std,%D0,%D1));
                    AS2 (std,%D0,%D1));
    }
    }
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
    return *l=4, (AS2 (st,%0,%D1) CR_TAB
    return *l=4, (AS2 (st,%0,%D1) CR_TAB
                  AS2 (st,%0,%C1) CR_TAB
                  AS2 (st,%0,%C1) CR_TAB
                  AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%A1));
                  AS2 (st,%0,%A1));
  else if (GET_CODE (base) == POST_INC) /* (R++) */
  else if (GET_CODE (base) == POST_INC) /* (R++) */
    return *l=4, (AS2 (st,%0,%A1)  CR_TAB
    return *l=4, (AS2 (st,%0,%A1)  CR_TAB
                  AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%C1) CR_TAB
                  AS2 (st,%0,%C1) CR_TAB
                  AS2 (st,%0,%D1));
                  AS2 (st,%0,%D1));
  fatal_insn ("unknown move insn:",insn);
  fatal_insn ("unknown move insn:",insn);
  return "";
  return "";
}
}
 
 
const char *
const char *
output_movsisf(rtx insn, rtx operands[], int *l)
output_movsisf(rtx insn, rtx operands[], int *l)
{
{
  int dummy;
  int dummy;
  rtx dest = operands[0];
  rtx dest = operands[0];
  rtx src = operands[1];
  rtx src = operands[1];
  int *real_l = l;
  int *real_l = l;
 
 
  if (!l)
  if (!l)
    l = &dummy;
    l = &dummy;
 
 
  if (register_operand (dest, VOIDmode))
  if (register_operand (dest, VOIDmode))
    {
    {
      if (register_operand (src, VOIDmode)) /* mov r,r */
      if (register_operand (src, VOIDmode)) /* mov r,r */
        {
        {
          if (true_regnum (dest) > true_regnum (src))
          if (true_regnum (dest) > true_regnum (src))
            {
            {
              if (AVR_HAVE_MOVW)
              if (AVR_HAVE_MOVW)
                {
                {
                  *l = 2;
                  *l = 2;
                  return (AS2 (movw,%C0,%C1) CR_TAB
                  return (AS2 (movw,%C0,%C1) CR_TAB
                          AS2 (movw,%A0,%A1));
                          AS2 (movw,%A0,%A1));
                }
                }
              *l = 4;
              *l = 4;
              return (AS2 (mov,%D0,%D1) CR_TAB
              return (AS2 (mov,%D0,%D1) CR_TAB
                      AS2 (mov,%C0,%C1) CR_TAB
                      AS2 (mov,%C0,%C1) CR_TAB
                      AS2 (mov,%B0,%B1) CR_TAB
                      AS2 (mov,%B0,%B1) CR_TAB
                      AS2 (mov,%A0,%A1));
                      AS2 (mov,%A0,%A1));
            }
            }
          else
          else
            {
            {
              if (AVR_HAVE_MOVW)
              if (AVR_HAVE_MOVW)
                {
                {
                  *l = 2;
                  *l = 2;
                  return (AS2 (movw,%A0,%A1) CR_TAB
                  return (AS2 (movw,%A0,%A1) CR_TAB
                          AS2 (movw,%C0,%C1));
                          AS2 (movw,%C0,%C1));
                }
                }
              *l = 4;
              *l = 4;
              return (AS2 (mov,%A0,%A1) CR_TAB
              return (AS2 (mov,%A0,%A1) CR_TAB
                      AS2 (mov,%B0,%B1) CR_TAB
                      AS2 (mov,%B0,%B1) CR_TAB
                      AS2 (mov,%C0,%C1) CR_TAB
                      AS2 (mov,%C0,%C1) CR_TAB
                      AS2 (mov,%D0,%D1));
                      AS2 (mov,%D0,%D1));
            }
            }
        }
        }
      else if (CONSTANT_P (src))
      else if (CONSTANT_P (src))
        {
        {
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
          if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
            {
            {
              *l = 4;
              *l = 4;
              return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
              return (AS2 (ldi,%A0,lo8(%1))  CR_TAB
                      AS2 (ldi,%B0,hi8(%1))  CR_TAB
                      AS2 (ldi,%B0,hi8(%1))  CR_TAB
                      AS2 (ldi,%C0,hlo8(%1)) CR_TAB
                      AS2 (ldi,%C0,hlo8(%1)) CR_TAB
                      AS2 (ldi,%D0,hhi8(%1)));
                      AS2 (ldi,%D0,hhi8(%1)));
            }
            }
 
 
          if (GET_CODE (src) == CONST_INT)
          if (GET_CODE (src) == CONST_INT)
            {
            {
              const char *const clr_op0 =
              const char *const clr_op0 =
                AVR_HAVE_MOVW ? (AS1 (clr,%A0) CR_TAB
                AVR_HAVE_MOVW ? (AS1 (clr,%A0) CR_TAB
                                AS1 (clr,%B0) CR_TAB
                                AS1 (clr,%B0) CR_TAB
                                AS2 (movw,%C0,%A0))
                                AS2 (movw,%C0,%A0))
                             : (AS1 (clr,%A0) CR_TAB
                             : (AS1 (clr,%A0) CR_TAB
                                AS1 (clr,%B0) CR_TAB
                                AS1 (clr,%B0) CR_TAB
                                AS1 (clr,%C0) CR_TAB
                                AS1 (clr,%C0) CR_TAB
                                AS1 (clr,%D0));
                                AS1 (clr,%D0));
 
 
              if (src == const0_rtx) /* mov r,L */
              if (src == const0_rtx) /* mov r,L */
                {
                {
                  *l = AVR_HAVE_MOVW ? 3 : 4;
                  *l = AVR_HAVE_MOVW ? 3 : 4;
                  return clr_op0;
                  return clr_op0;
                }
                }
              else if (src == const1_rtx)
              else if (src == const1_rtx)
                {
                {
                  if (!real_l)
                  if (!real_l)
                    output_asm_insn (clr_op0, operands);
                    output_asm_insn (clr_op0, operands);
                  *l = AVR_HAVE_MOVW ? 4 : 5;
                  *l = AVR_HAVE_MOVW ? 4 : 5;
                  return AS1 (inc,%A0);
                  return AS1 (inc,%A0);
                }
                }
              else if (src == constm1_rtx)
              else if (src == constm1_rtx)
                {
                {
                  /* Immediate constants -1 to any register */
                  /* Immediate constants -1 to any register */
                  if (AVR_HAVE_MOVW)
                  if (AVR_HAVE_MOVW)
                    {
                    {
                      *l = 4;
                      *l = 4;
                      return (AS1 (clr,%A0)     CR_TAB
                      return (AS1 (clr,%A0)     CR_TAB
                              AS1 (dec,%A0)     CR_TAB
                              AS1 (dec,%A0)     CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
                              AS2 (movw,%C0,%A0));
                              AS2 (movw,%C0,%A0));
                    }
                    }
                  *l = 5;
                  *l = 5;
                  return (AS1 (clr,%A0)     CR_TAB
                  return (AS1 (clr,%A0)     CR_TAB
                          AS1 (dec,%A0)     CR_TAB
                          AS1 (dec,%A0)     CR_TAB
                          AS2 (mov,%B0,%A0) CR_TAB
                          AS2 (mov,%B0,%A0) CR_TAB
                          AS2 (mov,%C0,%A0) CR_TAB
                          AS2 (mov,%C0,%A0) CR_TAB
                          AS2 (mov,%D0,%A0));
                          AS2 (mov,%D0,%A0));
                }
                }
              else
              else
                {
                {
                  int bit_nr = exact_log2 (INTVAL (src));
                  int bit_nr = exact_log2 (INTVAL (src));
 
 
                  if (bit_nr >= 0)
                  if (bit_nr >= 0)
                    {
                    {
                      *l = AVR_HAVE_MOVW ? 5 : 6;
                      *l = AVR_HAVE_MOVW ? 5 : 6;
                      if (!real_l)
                      if (!real_l)
                        {
                        {
                          output_asm_insn (clr_op0, operands);
                          output_asm_insn (clr_op0, operands);
                          output_asm_insn ("set", operands);
                          output_asm_insn ("set", operands);
                        }
                        }
                      if (!real_l)
                      if (!real_l)
                        avr_output_bld (operands, bit_nr);
                        avr_output_bld (operands, bit_nr);
 
 
                      return "";
                      return "";
                    }
                    }
                }
                }
            }
            }
 
 
          /* Last resort, better than loading from memory.  */
          /* Last resort, better than loading from memory.  */
          *l = 10;
          *l = 10;
          return (AS2 (mov,__tmp_reg__,r31) CR_TAB
          return (AS2 (mov,__tmp_reg__,r31) CR_TAB
                  AS2 (ldi,r31,lo8(%1))     CR_TAB
                  AS2 (ldi,r31,lo8(%1))     CR_TAB
                  AS2 (mov,%A0,r31)         CR_TAB
                  AS2 (mov,%A0,r31)         CR_TAB
                  AS2 (ldi,r31,hi8(%1))     CR_TAB
                  AS2 (ldi,r31,hi8(%1))     CR_TAB
                  AS2 (mov,%B0,r31)         CR_TAB
                  AS2 (mov,%B0,r31)         CR_TAB
                  AS2 (ldi,r31,hlo8(%1))    CR_TAB
                  AS2 (ldi,r31,hlo8(%1))    CR_TAB
                  AS2 (mov,%C0,r31)         CR_TAB
                  AS2 (mov,%C0,r31)         CR_TAB
                  AS2 (ldi,r31,hhi8(%1))    CR_TAB
                  AS2 (ldi,r31,hhi8(%1))    CR_TAB
                  AS2 (mov,%D0,r31)         CR_TAB
                  AS2 (mov,%D0,r31)         CR_TAB
                  AS2 (mov,r31,__tmp_reg__));
                  AS2 (mov,r31,__tmp_reg__));
        }
        }
      else if (GET_CODE (src) == MEM)
      else if (GET_CODE (src) == MEM)
        return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */
        return out_movsi_r_mr (insn, operands, real_l); /* mov r,m */
    }
    }
  else if (GET_CODE (dest) == MEM)
  else if (GET_CODE (dest) == MEM)
    {
    {
      const char *template;
      const char *template;
 
 
      if (src == const0_rtx)
      if (src == const0_rtx)
          operands[1] = zero_reg_rtx;
          operands[1] = zero_reg_rtx;
 
 
      template = out_movsi_mr_r (insn, operands, real_l);
      template = out_movsi_mr_r (insn, operands, real_l);
 
 
      if (!real_l)
      if (!real_l)
        output_asm_insn (template, operands);
        output_asm_insn (template, operands);
 
 
      operands[1] = src;
      operands[1] = src;
      return "";
      return "";
    }
    }
  fatal_insn ("invalid insn:", insn);
  fatal_insn ("invalid insn:", insn);
  return "";
  return "";
}
}
 
 
const char *
const char *
out_movqi_mr_r (rtx insn, rtx op[], int *l)
out_movqi_mr_r (rtx insn, rtx op[], int *l)
{
{
  rtx dest = op[0];
  rtx dest = op[0];
  rtx src = op[1];
  rtx src = op[1];
  rtx x = XEXP (dest, 0);
  rtx x = XEXP (dest, 0);
  int dummy;
  int dummy;
 
 
  if (!l)
  if (!l)
    l = &dummy;
    l = &dummy;
 
 
  if (CONSTANT_ADDRESS_P (x))
  if (CONSTANT_ADDRESS_P (x))
    {
    {
      if (avr_io_address_p (x, 1))
      if (avr_io_address_p (x, 1))
        {
        {
          *l = 1;
          *l = 1;
          return AS2 (out,%0-0x20,%1);
          return AS2 (out,%0-0x20,%1);
        }
        }
      *l = 2;
      *l = 2;
      return AS2 (sts,%0,%1);
      return AS2 (sts,%0,%1);
    }
    }
  /* memory access by reg+disp */
  /* memory access by reg+disp */
  else if (GET_CODE (x) == PLUS
  else if (GET_CODE (x) == PLUS
      && REG_P (XEXP (x,0))
      && REG_P (XEXP (x,0))
      && GET_CODE (XEXP (x,1)) == CONST_INT)
      && GET_CODE (XEXP (x,1)) == CONST_INT)
    {
    {
      if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (dest))) >= 63)
      if ((INTVAL (XEXP (x,1)) - GET_MODE_SIZE (GET_MODE (dest))) >= 63)
        {
        {
          int disp = INTVAL (XEXP (x,1));
          int disp = INTVAL (XEXP (x,1));
          if (REGNO (XEXP (x,0)) != REG_Y)
          if (REGNO (XEXP (x,0)) != REG_Y)
            fatal_insn ("incorrect insn:",insn);
            fatal_insn ("incorrect insn:",insn);
 
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
            return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
            return *l = 3, (AS2 (adiw,r28,%o0-63) CR_TAB
                            AS2 (std,Y+63,%1)     CR_TAB
                            AS2 (std,Y+63,%1)     CR_TAB
                            AS2 (sbiw,r28,%o0-63));
                            AS2 (sbiw,r28,%o0-63));
 
 
          return *l = 5, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
          return *l = 5, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o0)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o0)) CR_TAB
                          AS2 (st,Y,%1)            CR_TAB
                          AS2 (st,Y,%1)            CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (sbci,r29,hi8(%o0)));
                          AS2 (sbci,r29,hi8(%o0)));
        }
        }
      else if (REGNO (XEXP (x,0)) == REG_X)
      else if (REGNO (XEXP (x,0)) == REG_X)
        {
        {
          if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
          if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
            {
            {
              if (reg_unused_after (insn, XEXP (x,0)))
              if (reg_unused_after (insn, XEXP (x,0)))
                return *l = 3, (AS2 (mov,__tmp_reg__,%1) CR_TAB
                return *l = 3, (AS2 (mov,__tmp_reg__,%1) CR_TAB
                                AS2 (adiw,r26,%o0)       CR_TAB
                                AS2 (adiw,r26,%o0)       CR_TAB
                                AS2 (st,X,__tmp_reg__));
                                AS2 (st,X,__tmp_reg__));
 
 
              return *l = 4, (AS2 (mov,__tmp_reg__,%1) CR_TAB
              return *l = 4, (AS2 (mov,__tmp_reg__,%1) CR_TAB
                              AS2 (adiw,r26,%o0)       CR_TAB
                              AS2 (adiw,r26,%o0)       CR_TAB
                              AS2 (st,X,__tmp_reg__)   CR_TAB
                              AS2 (st,X,__tmp_reg__)   CR_TAB
                              AS2 (sbiw,r26,%o0));
                              AS2 (sbiw,r26,%o0));
            }
            }
          else
          else
            {
            {
              if (reg_unused_after (insn, XEXP (x,0)))
              if (reg_unused_after (insn, XEXP (x,0)))
                return *l = 2, (AS2 (adiw,r26,%o0) CR_TAB
                return *l = 2, (AS2 (adiw,r26,%o0) CR_TAB
                                AS2 (st,X,%1));
                                AS2 (st,X,%1));
 
 
              return *l = 3, (AS2 (adiw,r26,%o0) CR_TAB
              return *l = 3, (AS2 (adiw,r26,%o0) CR_TAB
                              AS2 (st,X,%1)      CR_TAB
                              AS2 (st,X,%1)      CR_TAB
                              AS2 (sbiw,r26,%o0));
                              AS2 (sbiw,r26,%o0));
            }
            }
        }
        }
      *l = 1;
      *l = 1;
      return AS2 (std,%0,%1);
      return AS2 (std,%0,%1);
    }
    }
  *l = 1;
  *l = 1;
  return AS2 (st,%0,%1);
  return AS2 (st,%0,%1);
}
}
 
 
const char *
const char *
out_movhi_mr_r (rtx insn, rtx op[], int *l)
out_movhi_mr_r (rtx insn, rtx op[], int *l)
{
{
  rtx dest = op[0];
  rtx dest = op[0];
  rtx src = op[1];
  rtx src = op[1];
  rtx base = XEXP (dest, 0);
  rtx base = XEXP (dest, 0);
  int reg_base = true_regnum (base);
  int reg_base = true_regnum (base);
  int reg_src = true_regnum (src);
  int reg_src = true_regnum (src);
  /* "volatile" forces writing high byte first, even if less efficient,
  /* "volatile" forces writing high byte first, even if less efficient,
     for correct operation with 16-bit I/O registers.  */
     for correct operation with 16-bit I/O registers.  */
  int mem_volatile_p = MEM_VOLATILE_P (dest);
  int mem_volatile_p = MEM_VOLATILE_P (dest);
  int tmp;
  int tmp;
 
 
  if (!l)
  if (!l)
    l = &tmp;
    l = &tmp;
  if (CONSTANT_ADDRESS_P (base))
  if (CONSTANT_ADDRESS_P (base))
    {
    {
      if (avr_io_address_p (base, 2))
      if (avr_io_address_p (base, 2))
        {
        {
          *l = 2;
          *l = 2;
          return (AS2 (out,%B0-0x20,%B1) CR_TAB
          return (AS2 (out,%B0-0x20,%B1) CR_TAB
                  AS2 (out,%A0-0x20,%A1));
                  AS2 (out,%A0-0x20,%A1));
        }
        }
      return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
      return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
                      AS2 (sts,%A0,%A1));
                      AS2 (sts,%A0,%A1));
    }
    }
  if (reg_base > 0)
  if (reg_base > 0)
    {
    {
      if (reg_base == REG_X)
      if (reg_base == REG_X)
        {
        {
          if (reg_src == REG_X)
          if (reg_src == REG_X)
            {
            {
              /* "st X+,r26" and "st -X,r26" are undefined.  */
              /* "st X+,r26" and "st -X,r26" are undefined.  */
              if (!mem_volatile_p && reg_unused_after (insn, src))
              if (!mem_volatile_p && reg_unused_after (insn, src))
                return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                return *l=4, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                              AS2 (st,X,r26)            CR_TAB
                              AS2 (st,X,r26)            CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (st,X,__tmp_reg__));
                              AS2 (st,X,__tmp_reg__));
              else
              else
                return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (adiw,r26,1)          CR_TAB
                              AS2 (st,X,__tmp_reg__)    CR_TAB
                              AS2 (st,X,__tmp_reg__)    CR_TAB
                              AS2 (sbiw,r26,1)          CR_TAB
                              AS2 (sbiw,r26,1)          CR_TAB
                              AS2 (st,X,r26));
                              AS2 (st,X,r26));
            }
            }
          else
          else
            {
            {
              if (!mem_volatile_p && reg_unused_after (insn, base))
              if (!mem_volatile_p && reg_unused_after (insn, base))
                return *l=2, (AS2 (st,X+,%A1) CR_TAB
                return *l=2, (AS2 (st,X+,%A1) CR_TAB
                              AS2 (st,X,%B1));
                              AS2 (st,X,%B1));
              else
              else
                return *l=3, (AS2 (adiw,r26,1) CR_TAB
                return *l=3, (AS2 (adiw,r26,1) CR_TAB
                              AS2 (st,X,%B1)   CR_TAB
                              AS2 (st,X,%B1)   CR_TAB
                              AS2 (st,-X,%A1));
                              AS2 (st,-X,%A1));
            }
            }
        }
        }
      else
      else
        return  *l=2, (AS2 (std,%0+1,%B1) CR_TAB
        return  *l=2, (AS2 (std,%0+1,%B1) CR_TAB
                       AS2 (st,%0,%A1));
                       AS2 (st,%0,%A1));
    }
    }
  else if (GET_CODE (base) == PLUS)
  else if (GET_CODE (base) == PLUS)
    {
    {
      int disp = INTVAL (XEXP (base, 1));
      int disp = INTVAL (XEXP (base, 1));
      reg_base = REGNO (XEXP (base, 0));
      reg_base = REGNO (XEXP (base, 0));
      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
        {
        {
          if (reg_base != REG_Y)
          if (reg_base != REG_Y)
            fatal_insn ("incorrect insn:",insn);
            fatal_insn ("incorrect insn:",insn);
 
 
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
          if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
            return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
            return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
                            AS2 (std,Y+63,%B1)    CR_TAB
                            AS2 (std,Y+63,%B1)    CR_TAB
                            AS2 (std,Y+62,%A1)    CR_TAB
                            AS2 (std,Y+62,%A1)    CR_TAB
                            AS2 (sbiw,r28,%o0-62));
                            AS2 (sbiw,r28,%o0-62));
 
 
          return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
          return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o0)) CR_TAB
                          AS2 (sbci,r29,hi8(-%o0)) CR_TAB
                          AS2 (std,Y+1,%B1)        CR_TAB
                          AS2 (std,Y+1,%B1)        CR_TAB
                          AS2 (st,Y,%A1)           CR_TAB
                          AS2 (st,Y,%A1)           CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (subi,r28,lo8(%o0))  CR_TAB
                          AS2 (sbci,r29,hi8(%o0)));
                          AS2 (sbci,r29,hi8(%o0)));
        }
        }
      if (reg_base == REG_X)
      if (reg_base == REG_X)
        {
        {
          /* (X + d) = R */
          /* (X + d) = R */
          if (reg_src == REG_X)
          if (reg_src == REG_X)
            {
            {
              *l = 7;
              *l = 7;
              return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
              return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
                      AS2 (mov,__zero_reg__,r27) CR_TAB
                      AS2 (mov,__zero_reg__,r27) CR_TAB
                      AS2 (adiw,r26,%o0+1)       CR_TAB
                      AS2 (adiw,r26,%o0+1)       CR_TAB
                      AS2 (st,X,__zero_reg__)    CR_TAB
                      AS2 (st,X,__zero_reg__)    CR_TAB
                      AS2 (st,-X,__tmp_reg__)    CR_TAB
                      AS2 (st,-X,__tmp_reg__)    CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
                      AS1 (clr,__zero_reg__)     CR_TAB
                      AS2 (sbiw,r26,%o0));
                      AS2 (sbiw,r26,%o0));
            }
            }
          *l = 4;
          *l = 4;
          return (AS2 (adiw,r26,%o0+1) CR_TAB
          return (AS2 (adiw,r26,%o0+1) CR_TAB
                  AS2 (st,X,%B1)       CR_TAB
                  AS2 (st,X,%B1)       CR_TAB
                  AS2 (st,-X,%A1)      CR_TAB
                  AS2 (st,-X,%A1)      CR_TAB
                  AS2 (sbiw,r26,%o0));
                  AS2 (sbiw,r26,%o0));
        }
        }
      return *l=2, (AS2 (std,%B0,%B1)    CR_TAB
      return *l=2, (AS2 (std,%B0,%B1)    CR_TAB
                    AS2 (std,%A0,%A1));
                    AS2 (std,%A0,%A1));
    }
    }
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
    return *l=2, (AS2 (st,%0,%B1) CR_TAB
    return *l=2, (AS2 (st,%0,%B1) CR_TAB
                  AS2 (st,%0,%A1));
                  AS2 (st,%0,%A1));
  else if (GET_CODE (base) == POST_INC) /* (R++) */
  else if (GET_CODE (base) == POST_INC) /* (R++) */
    {
    {
      if (mem_volatile_p)
      if (mem_volatile_p)
        {
        {
          if (REGNO (XEXP (base, 0)) == REG_X)
          if (REGNO (XEXP (base, 0)) == REG_X)
            {
            {
              *l = 4;
              *l = 4;
              return (AS2 (adiw,r26,1)  CR_TAB
              return (AS2 (adiw,r26,1)  CR_TAB
                      AS2 (st,X,%B1)    CR_TAB
                      AS2 (st,X,%B1)    CR_TAB
                      AS2 (st,-X,%A1)   CR_TAB
                      AS2 (st,-X,%A1)   CR_TAB
                      AS2 (adiw,r26,2));
                      AS2 (adiw,r26,2));
            }
            }
          else
          else
            {
            {
              *l = 3;
              *l = 3;
              return (AS2 (std,%p0+1,%B1) CR_TAB
              return (AS2 (std,%p0+1,%B1) CR_TAB
                      AS2 (st,%p0,%A1)    CR_TAB
                      AS2 (st,%p0,%A1)    CR_TAB
                      AS2 (adiw,%r0,2));
                      AS2 (adiw,%r0,2));
            }
            }
        }
        }
 
 
      *l = 2;
      *l = 2;
      return (AS2 (st,%0,%A1)  CR_TAB
      return (AS2 (st,%0,%A1)  CR_TAB
            AS2 (st,%0,%B1));
            AS2 (st,%0,%B1));
    }
    }
  fatal_insn ("unknown move insn:",insn);
  fatal_insn ("unknown move insn:",insn);
  return "";
  return "";
}
}
 
 
/* Return 1 if frame pointer for current function required.  */
/* Return 1 if frame pointer for current function required.  */
 
 
int
int
frame_pointer_required_p (void)
frame_pointer_required_p (void)
{
{
  return (current_function_calls_alloca
  return (current_function_calls_alloca
          || current_function_args_info.nregs == 0
          || current_function_args_info.nregs == 0
          || get_frame_size () > 0);
          || get_frame_size () > 0);
}
}
 
 
/* Returns the condition of compare insn INSN, or UNKNOWN.  */
/* Returns the condition of compare insn INSN, or UNKNOWN.  */
 
 
static RTX_CODE
static RTX_CODE
compare_condition (rtx insn)
compare_condition (rtx insn)
{
{
  rtx next = next_real_insn (insn);
  rtx next = next_real_insn (insn);
  RTX_CODE cond = UNKNOWN;
  RTX_CODE cond = UNKNOWN;
  if (next && GET_CODE (next) == JUMP_INSN)
  if (next && GET_CODE (next) == JUMP_INSN)
    {
    {
      rtx pat = PATTERN (next);
      rtx pat = PATTERN (next);
      rtx src = SET_SRC (pat);
      rtx src = SET_SRC (pat);
      rtx t = XEXP (src, 0);
      rtx t = XEXP (src, 0);
      cond = GET_CODE (t);
      cond = GET_CODE (t);
    }
    }
  return cond;
  return cond;
}
}
 
 
/* Returns nonzero if INSN is a tst insn that only tests the sign.  */
/* Returns nonzero if INSN is a tst insn that only tests the sign.  */
 
 
static int
static int
compare_sign_p (rtx insn)
compare_sign_p (rtx insn)
{
{
  RTX_CODE cond = compare_condition (insn);
  RTX_CODE cond = compare_condition (insn);
  return (cond == GE || cond == LT);
  return (cond == GE || cond == LT);
}
}
 
 
/* Returns nonzero if the next insn is a JUMP_INSN with a condition
/* Returns nonzero if the next insn is a JUMP_INSN with a condition
   that needs to be swapped (GT, GTU, LE, LEU).  */
   that needs to be swapped (GT, GTU, LE, LEU).  */
 
 
int
int
compare_diff_p (rtx insn)
compare_diff_p (rtx insn)
{
{
  RTX_CODE cond = compare_condition (insn);
  RTX_CODE cond = compare_condition (insn);
  return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
  return (cond == GT || cond == GTU || cond == LE || cond == LEU) ? cond : 0;
}
}
 
 
/* Returns nonzero if INSN is a compare insn with the EQ or NE condition.  */
/* Returns nonzero if INSN is a compare insn with the EQ or NE condition.  */
 
 
int
int
compare_eq_p (rtx insn)
compare_eq_p (rtx insn)
{
{
  RTX_CODE cond = compare_condition (insn);
  RTX_CODE cond = compare_condition (insn);
  return (cond == EQ || cond == NE);
  return (cond == EQ || cond == NE);
}
}
 
 
 
 
/* Output test instruction for HImode.  */
/* Output test instruction for HImode.  */
 
 
const char *
const char *
out_tsthi (rtx insn, int *l)
out_tsthi (rtx insn, int *l)
{
{
  if (compare_sign_p (insn))
  if (compare_sign_p (insn))
    {
    {
      if (l) *l = 1;
      if (l) *l = 1;
      return AS1 (tst,%B0);
      return AS1 (tst,%B0);
    }
    }
  if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
  if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
      && compare_eq_p (insn))
      && compare_eq_p (insn))
    {
    {
      /* Faster than sbiw if we can clobber the operand.  */
      /* Faster than sbiw if we can clobber the operand.  */
      if (l) *l = 1;
      if (l) *l = 1;
      return AS2 (or,%A0,%B0);
      return AS2 (or,%A0,%B0);
    }
    }
  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
    {
    {
      if (l) *l = 1;
      if (l) *l = 1;
      return AS2 (sbiw,%0,0);
      return AS2 (sbiw,%0,0);
    }
    }
  if (l) *l = 2;
  if (l) *l = 2;
  return (AS2 (cp,%A0,__zero_reg__) CR_TAB
  return (AS2 (cp,%A0,__zero_reg__) CR_TAB
          AS2 (cpc,%B0,__zero_reg__));
          AS2 (cpc,%B0,__zero_reg__));
}
}
 
 
 
 
/* Output test instruction for SImode.  */
/* Output test instruction for SImode.  */
 
 
const char *
const char *
out_tstsi (rtx insn, int *l)
out_tstsi (rtx insn, int *l)
{
{
  if (compare_sign_p (insn))
  if (compare_sign_p (insn))
    {
    {
      if (l) *l = 1;
      if (l) *l = 1;
      return AS1 (tst,%D0);
      return AS1 (tst,%D0);
    }
    }
  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
    {
    {
      if (l) *l = 3;
      if (l) *l = 3;
      return (AS2 (sbiw,%A0,0) CR_TAB
      return (AS2 (sbiw,%A0,0) CR_TAB
              AS2 (cpc,%C0,__zero_reg__) CR_TAB
              AS2 (cpc,%C0,__zero_reg__) CR_TAB
              AS2 (cpc,%D0,__zero_reg__));
              AS2 (cpc,%D0,__zero_reg__));
    }
    }
  if (l) *l = 4;
  if (l) *l = 4;
  return (AS2 (cp,%A0,__zero_reg__) CR_TAB
  return (AS2 (cp,%A0,__zero_reg__) CR_TAB
          AS2 (cpc,%B0,__zero_reg__) CR_TAB
          AS2 (cpc,%B0,__zero_reg__) CR_TAB
          AS2 (cpc,%C0,__zero_reg__) CR_TAB
          AS2 (cpc,%C0,__zero_reg__) CR_TAB
          AS2 (cpc,%D0,__zero_reg__));
          AS2 (cpc,%D0,__zero_reg__));
}
}
 
 
 
 
/* Generate asm equivalent for various shifts.
/* Generate asm equivalent for various shifts.
   Shift count is a CONST_INT, MEM or REG.
   Shift count is a CONST_INT, MEM or REG.
   This only handles cases that are not already
   This only handles cases that are not already
   carefully hand-optimized in ?sh??i3_out.  */
   carefully hand-optimized in ?sh??i3_out.  */
 
 
void
void
out_shift_with_cnt (const char *template, rtx insn, rtx operands[],
out_shift_with_cnt (const char *template, rtx insn, rtx operands[],
                    int *len, int t_len)
                    int *len, int t_len)
{
{
  rtx op[10];
  rtx op[10];
  char str[500];
  char str[500];
  int second_label = 1;
  int second_label = 1;
  int saved_in_tmp = 0;
  int saved_in_tmp = 0;
  int use_zero_reg = 0;
  int use_zero_reg = 0;
 
 
  op[0] = operands[0];
  op[0] = operands[0];
  op[1] = operands[1];
  op[1] = operands[1];
  op[2] = operands[2];
  op[2] = operands[2];
  op[3] = operands[3];
  op[3] = operands[3];
  str[0] = 0;
  str[0] = 0;
 
 
  if (len)
  if (len)
    *len = 1;
    *len = 1;
 
 
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int count = INTVAL (operands[2]);
      int count = INTVAL (operands[2]);
      int max_len = 10;  /* If larger than this, always use a loop.  */
      int max_len = 10;  /* If larger than this, always use a loop.  */
 
 
      if (count <= 0)
      if (count <= 0)
        {
        {
          if (len)
          if (len)
            *len = 0;
            *len = 0;
          return;
          return;
        }
        }
 
 
      if (count < 8 && !scratch)
      if (count < 8 && !scratch)
        use_zero_reg = 1;
        use_zero_reg = 1;
 
 
      if (optimize_size)
      if (optimize_size)
        max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
        max_len = t_len + (scratch ? 3 : (use_zero_reg ? 4 : 5));
 
 
      if (t_len * count <= max_len)
      if (t_len * count <= max_len)
        {
        {
          /* Output shifts inline with no loop - faster.  */
          /* Output shifts inline with no loop - faster.  */
          if (len)
          if (len)
            *len = t_len * count;
            *len = t_len * count;
          else
          else
            {
            {
              while (count-- > 0)
              while (count-- > 0)
                output_asm_insn (template, op);
                output_asm_insn (template, op);
            }
            }
 
 
          return;
          return;
        }
        }
 
 
      if (scratch)
      if (scratch)
        {
        {
          if (!len)
          if (!len)
            strcat (str, AS2 (ldi,%3,%2));
            strcat (str, AS2 (ldi,%3,%2));
        }
        }
      else if (use_zero_reg)
      else if (use_zero_reg)
        {
        {
          /* Hack to save one word: use __zero_reg__ as loop counter.
          /* Hack to save one word: use __zero_reg__ as loop counter.
             Set one bit, then shift in a loop until it is 0 again.  */
             Set one bit, then shift in a loop until it is 0 again.  */
 
 
          op[3] = zero_reg_rtx;
          op[3] = zero_reg_rtx;
          if (len)
          if (len)
            *len = 2;
            *len = 2;
          else
          else
            strcat (str, ("set" CR_TAB
            strcat (str, ("set" CR_TAB
                          AS2 (bld,%3,%2-1)));
                          AS2 (bld,%3,%2-1)));
        }
        }
      else
      else
        {
        {
          /* No scratch register available, use one from LD_REGS (saved in
          /* No scratch register available, use one from LD_REGS (saved in
             __tmp_reg__) that doesn't overlap with registers to shift.  */
             __tmp_reg__) that doesn't overlap with registers to shift.  */
 
 
          op[3] = gen_rtx_REG (QImode,
          op[3] = gen_rtx_REG (QImode,
                           ((true_regnum (operands[0]) - 1) & 15) + 16);
                           ((true_regnum (operands[0]) - 1) & 15) + 16);
          op[4] = tmp_reg_rtx;
          op[4] = tmp_reg_rtx;
          saved_in_tmp = 1;
          saved_in_tmp = 1;
 
 
          if (len)
          if (len)
            *len = 3;  /* Includes "mov %3,%4" after the loop.  */
            *len = 3;  /* Includes "mov %3,%4" after the loop.  */
          else
          else
            strcat (str, (AS2 (mov,%4,%3) CR_TAB
            strcat (str, (AS2 (mov,%4,%3) CR_TAB
                          AS2 (ldi,%3,%2)));
                          AS2 (ldi,%3,%2)));
        }
        }
 
 
      second_label = 0;
      second_label = 0;
    }
    }
  else if (GET_CODE (operands[2]) == MEM)
  else if (GET_CODE (operands[2]) == MEM)
    {
    {
      rtx op_mov[10];
      rtx op_mov[10];
 
 
      op[3] = op_mov[0] = tmp_reg_rtx;
      op[3] = op_mov[0] = tmp_reg_rtx;
      op_mov[1] = op[2];
      op_mov[1] = op[2];
 
 
      if (len)
      if (len)
        out_movqi_r_mr (insn, op_mov, len);
        out_movqi_r_mr (insn, op_mov, len);
      else
      else
        output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
        output_asm_insn (out_movqi_r_mr (insn, op_mov, NULL), op_mov);
    }
    }
  else if (register_operand (operands[2], QImode))
  else if (register_operand (operands[2], QImode))
    {
    {
      if (reg_unused_after (insn, operands[2]))
      if (reg_unused_after (insn, operands[2]))
        op[3] = op[2];
        op[3] = op[2];
      else
      else
        {
        {
          op[3] = tmp_reg_rtx;
          op[3] = tmp_reg_rtx;
          if (!len)
          if (!len)
            strcat (str, (AS2 (mov,%3,%2) CR_TAB));
            strcat (str, (AS2 (mov,%3,%2) CR_TAB));
        }
        }
    }
    }
  else
  else
    fatal_insn ("bad shift insn:", insn);
    fatal_insn ("bad shift insn:", insn);
 
 
  if (second_label)
  if (second_label)
    {
    {
      if (len)
      if (len)
        ++*len;
        ++*len;
      else
      else
        strcat (str, AS1 (rjmp,2f));
        strcat (str, AS1 (rjmp,2f));
    }
    }
 
 
  if (len)
  if (len)
    *len += t_len + 2;  /* template + dec + brXX */
    *len += t_len + 2;  /* template + dec + brXX */
  else
  else
    {
    {
      strcat (str, "\n1:\t");
      strcat (str, "\n1:\t");
      strcat (str, template);
      strcat (str, template);
      strcat (str, second_label ? "\n2:\t" : "\n\t");
      strcat (str, second_label ? "\n2:\t" : "\n\t");
      strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
      strcat (str, use_zero_reg ? AS1 (lsr,%3) : AS1 (dec,%3));
      strcat (str, CR_TAB);
      strcat (str, CR_TAB);
      strcat (str, second_label ? AS1 (brpl,1b) : AS1 (brne,1b));
      strcat (str, second_label ? AS1 (brpl,1b) : AS1 (brne,1b));
      if (saved_in_tmp)
      if (saved_in_tmp)
        strcat (str, (CR_TAB AS2 (mov,%3,%4)));
        strcat (str, (CR_TAB AS2 (mov,%3,%4)));
      output_asm_insn (str, op);
      output_asm_insn (str, op);
    }
    }
}
}
 
 
 
 
/* 8bit shift left ((char)x << i)   */
/* 8bit shift left ((char)x << i)   */
 
 
const char *
const char *
ashlqi3_out (rtx insn, rtx operands[], int *len)
ashlqi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int k;
      int k;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        default:
        default:
          if (INTVAL (operands[2]) < 8)
          if (INTVAL (operands[2]) < 8)
            break;
            break;
 
 
          *len = 1;
          *len = 1;
          return AS1 (clr,%0);
          return AS1 (clr,%0);
 
 
        case 1:
        case 1:
          *len = 1;
          *len = 1;
          return AS1 (lsl,%0);
          return AS1 (lsl,%0);
 
 
        case 2:
        case 2:
          *len = 2;
          *len = 2;
          return (AS1 (lsl,%0) CR_TAB
          return (AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0));
                  AS1 (lsl,%0));
 
 
        case 3:
        case 3:
          *len = 3;
          *len = 3;
          return (AS1 (lsl,%0) CR_TAB
          return (AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0));
                  AS1 (lsl,%0));
 
 
        case 4:
        case 4:
          if (test_hard_reg_class (LD_REGS, operands[0]))
          if (test_hard_reg_class (LD_REGS, operands[0]))
            {
            {
              *len = 2;
              *len = 2;
              return (AS1 (swap,%0) CR_TAB
              return (AS1 (swap,%0) CR_TAB
                      AS2 (andi,%0,0xf0));
                      AS2 (andi,%0,0xf0));
            }
            }
          *len = 4;
          *len = 4;
          return (AS1 (lsl,%0) CR_TAB
          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));
                  AS1 (lsl,%0));
 
 
        case 5:
        case 5:
          if (test_hard_reg_class (LD_REGS, operands[0]))
          if (test_hard_reg_class (LD_REGS, operands[0]))
            {
            {
              *len = 3;
              *len = 3;
              return (AS1 (swap,%0) CR_TAB
              return (AS1 (swap,%0) CR_TAB
                      AS1 (lsl,%0)  CR_TAB
                      AS1 (lsl,%0)  CR_TAB
                      AS2 (andi,%0,0xe0));
                      AS2 (andi,%0,0xe0));
            }
            }
          *len = 5;
          *len = 5;
          return (AS1 (lsl,%0) CR_TAB
          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) CR_TAB
                  AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0));
                  AS1 (lsl,%0));
 
 
        case 6:
        case 6:
          if (test_hard_reg_class (LD_REGS, operands[0]))
          if (test_hard_reg_class (LD_REGS, operands[0]))
            {
            {
              *len = 4;
              *len = 4;
              return (AS1 (swap,%0) CR_TAB
              return (AS1 (swap,%0) CR_TAB
                      AS1 (lsl,%0)  CR_TAB
                      AS1 (lsl,%0)  CR_TAB
                      AS1 (lsl,%0)  CR_TAB
                      AS1 (lsl,%0)  CR_TAB
                      AS2 (andi,%0,0xc0));
                      AS2 (andi,%0,0xc0));
            }
            }
          *len = 6;
          *len = 6;
          return (AS1 (lsl,%0) CR_TAB
          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) CR_TAB
                  AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0) CR_TAB
                  AS1 (lsl,%0));
                  AS1 (lsl,%0));
 
 
        case 7:
        case 7:
          *len = 3;
          *len = 3;
          return (AS1 (ror,%0) CR_TAB
          return (AS1 (ror,%0) CR_TAB
                  AS1 (clr,%0) CR_TAB
                  AS1 (clr,%0) CR_TAB
                  AS1 (ror,%0));
                  AS1 (ror,%0));
        }
        }
    }
    }
  else if (CONSTANT_P (operands[2]))
  else if (CONSTANT_P (operands[2]))
    fatal_insn ("internal compiler error.  Incorrect shift:", insn);
    fatal_insn ("internal compiler error.  Incorrect shift:", insn);
 
 
  out_shift_with_cnt (AS1 (lsl,%0),
  out_shift_with_cnt (AS1 (lsl,%0),
                      insn, operands, len, 1);
                      insn, operands, len, 1);
  return "";
  return "";
}
}
 
 
 
 
/* 16bit shift left ((short)x << i)   */
/* 16bit shift left ((short)x << i)   */
 
 
const char *
const char *
ashlhi3_out (rtx insn, rtx operands[], int *len)
ashlhi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
      int k;
      int k;
      int *t = len;
      int *t = len;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        default:
        default:
          if (INTVAL (operands[2]) < 16)
          if (INTVAL (operands[2]) < 16)
            break;
            break;
 
 
          *len = 2;
          *len = 2;
          return (AS1 (clr,%B0) CR_TAB
          return (AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
 
 
        case 4:
        case 4:
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 6;
              *len = 6;
              return (AS1 (swap,%A0)      CR_TAB
              return (AS1 (swap,%A0)      CR_TAB
                      AS1 (swap,%B0)      CR_TAB
                      AS1 (swap,%B0)      CR_TAB
                      AS2 (andi,%B0,0xf0) CR_TAB
                      AS2 (andi,%B0,0xf0) CR_TAB
                      AS2 (eor,%B0,%A0)   CR_TAB
                      AS2 (eor,%B0,%A0)   CR_TAB
                      AS2 (andi,%A0,0xf0) CR_TAB
                      AS2 (andi,%A0,0xf0) CR_TAB
                      AS2 (eor,%B0,%A0));
                      AS2 (eor,%B0,%A0));
            }
            }
          if (scratch)
          if (scratch)
            {
            {
              *len = 7;
              *len = 7;
              return (AS1 (swap,%A0)    CR_TAB
              return (AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS2 (ldi,%3,0xf0) CR_TAB
                      AS2 (ldi,%3,0xf0) CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (eor,%B0,%A0) CR_TAB
                      AS2 (eor,%B0,%A0) CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (eor,%B0,%A0));
                      AS2 (eor,%B0,%A0));
            }
            }
          break;  /* optimize_size ? 6 : 8 */
          break;  /* optimize_size ? 6 : 8 */
 
 
        case 5:
        case 5:
          if (optimize_size)
          if (optimize_size)
            break;  /* scratch ? 5 : 6 */
            break;  /* scratch ? 5 : 6 */
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 8;
              *len = 8;
              return (AS1 (lsl,%A0)       CR_TAB
              return (AS1 (lsl,%A0)       CR_TAB
                      AS1 (rol,%B0)       CR_TAB
                      AS1 (rol,%B0)       CR_TAB
                      AS1 (swap,%A0)      CR_TAB
                      AS1 (swap,%A0)      CR_TAB
                      AS1 (swap,%B0)      CR_TAB
                      AS1 (swap,%B0)      CR_TAB
                      AS2 (andi,%B0,0xf0) CR_TAB
                      AS2 (andi,%B0,0xf0) CR_TAB
                      AS2 (eor,%B0,%A0)   CR_TAB
                      AS2 (eor,%B0,%A0)   CR_TAB
                      AS2 (andi,%A0,0xf0) CR_TAB
                      AS2 (andi,%A0,0xf0) CR_TAB
                      AS2 (eor,%B0,%A0));
                      AS2 (eor,%B0,%A0));
            }
            }
          if (scratch)
          if (scratch)
            {
            {
              *len = 9;
              *len = 9;
              return (AS1 (lsl,%A0)     CR_TAB
              return (AS1 (lsl,%A0)     CR_TAB
                      AS1 (rol,%B0)     CR_TAB
                      AS1 (rol,%B0)     CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS2 (ldi,%3,0xf0) CR_TAB
                      AS2 (ldi,%3,0xf0) CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (eor,%B0,%A0) CR_TAB
                      AS2 (eor,%B0,%A0) CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (eor,%B0,%A0));
                      AS2 (eor,%B0,%A0));
            }
            }
          break;  /* 10 */
          break;  /* 10 */
 
 
        case 6:
        case 6:
          if (optimize_size)
          if (optimize_size)
            break;  /* scratch ? 5 : 6 */
            break;  /* scratch ? 5 : 6 */
          *len = 9;
          *len = 9;
          return (AS1 (clr,__tmp_reg__) CR_TAB
          return (AS1 (clr,__tmp_reg__) CR_TAB
                  AS1 (lsr,%B0)         CR_TAB
                  AS1 (lsr,%B0)         CR_TAB
                  AS1 (ror,%A0)         CR_TAB
                  AS1 (ror,%A0)         CR_TAB
                  AS1 (ror,__tmp_reg__) CR_TAB
                  AS1 (ror,__tmp_reg__) CR_TAB
                  AS1 (lsr,%B0)         CR_TAB
                  AS1 (lsr,%B0)         CR_TAB
                  AS1 (ror,%A0)         CR_TAB
                  AS1 (ror,%A0)         CR_TAB
                  AS1 (ror,__tmp_reg__) CR_TAB
                  AS1 (ror,__tmp_reg__) CR_TAB
                  AS2 (mov,%B0,%A0)     CR_TAB
                  AS2 (mov,%B0,%A0)     CR_TAB
                  AS2 (mov,%A0,__tmp_reg__));
                  AS2 (mov,%A0,__tmp_reg__));
 
 
        case 7:
        case 7:
          *len = 5;
          *len = 5;
          return (AS1 (lsr,%B0)     CR_TAB
          return (AS1 (lsr,%B0)     CR_TAB
                  AS2 (mov,%B0,%A0) CR_TAB
                  AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (ror,%B0)     CR_TAB
                  AS1 (ror,%B0)     CR_TAB
                  AS1 (ror,%A0));
                  AS1 (ror,%A0));
 
 
        case 8:
        case 8:
          if (true_regnum (operands[0]) + 1 == true_regnum (operands[1]))
          if (true_regnum (operands[0]) + 1 == true_regnum (operands[1]))
            return *len = 1, AS1 (clr,%A0);
            return *len = 1, AS1 (clr,%A0);
          else
          else
            return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
            return *len = 2, (AS2 (mov,%B0,%A1) CR_TAB
                              AS1 (clr,%A0));
                              AS1 (clr,%A0));
 
 
        case 9:
        case 9:
          *len = 3;
          *len = 3;
          return (AS2 (mov,%B0,%A0) CR_TAB
          return (AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (lsl,%B0));
                  AS1 (lsl,%B0));
 
 
        case 10:
        case 10:
          *len = 4;
          *len = 4;
          return (AS2 (mov,%B0,%A0) CR_TAB
          return (AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0));
                  AS1 (lsl,%B0));
 
 
        case 11:
        case 11:
          *len = 5;
          *len = 5;
          return (AS2 (mov,%B0,%A0) CR_TAB
          return (AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0));
                  AS1 (lsl,%B0));
 
 
        case 12:
        case 12:
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 4;
              *len = 4;
              return (AS2 (mov,%B0,%A0) CR_TAB
              return (AS2 (mov,%B0,%A0) CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS2 (andi,%B0,0xf0));
                      AS2 (andi,%B0,0xf0));
            }
            }
          if (scratch)
          if (scratch)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (mov,%B0,%A0) CR_TAB
              return (AS2 (mov,%B0,%A0) CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS2 (ldi,%3,0xf0) CR_TAB
                      AS2 (ldi,%3,0xf0) CR_TAB
                      AS2 (and,%B0,%3));
                      AS2 (and,%B0,%3));
            }
            }
          *len = 6;
          *len = 6;
          return (AS2 (mov,%B0,%A0) CR_TAB
          return (AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0));
                  AS1 (lsl,%B0));
 
 
        case 13:
        case 13:
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (mov,%B0,%A0) CR_TAB
              return (AS2 (mov,%B0,%A0) CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (lsl,%B0)     CR_TAB
                      AS1 (lsl,%B0)     CR_TAB
                      AS2 (andi,%B0,0xe0));
                      AS2 (andi,%B0,0xe0));
            }
            }
          if (AVR_ENHANCED && scratch)
          if (AVR_ENHANCED && scratch)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%3,0x20) CR_TAB
              return (AS2 (ldi,%3,0x20) CR_TAB
                      AS2 (mul,%A0,%3)  CR_TAB
                      AS2 (mul,%A0,%3)  CR_TAB
                      AS2 (mov,%B0,r0)  CR_TAB
                      AS2 (mov,%B0,r0)  CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          if (scratch)
          if (scratch)
            {
            {
              *len = 6;
              *len = 6;
              return (AS2 (mov,%B0,%A0) CR_TAB
              return (AS2 (mov,%B0,%A0) CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (lsl,%B0)     CR_TAB
                      AS1 (lsl,%B0)     CR_TAB
                      AS2 (ldi,%3,0xe0) CR_TAB
                      AS2 (ldi,%3,0xe0) CR_TAB
                      AS2 (and,%B0,%3));
                      AS2 (and,%B0,%3));
            }
            }
          if (AVR_ENHANCED)
          if (AVR_ENHANCED)
            {
            {
              *len = 6;
              *len = 6;
              return ("set"            CR_TAB
              return ("set"            CR_TAB
                      AS2 (bld,r1,5)   CR_TAB
                      AS2 (bld,r1,5)   CR_TAB
                      AS2 (mul,%A0,r1) CR_TAB
                      AS2 (mul,%A0,r1) CR_TAB
                      AS2 (mov,%B0,r0) CR_TAB
                      AS2 (mov,%B0,r0) CR_TAB
                      AS1 (clr,%A0)    CR_TAB
                      AS1 (clr,%A0)    CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          *len = 7;
          *len = 7;
          return (AS2 (mov,%B0,%A0) CR_TAB
          return (AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (clr,%A0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0));
                  AS1 (lsl,%B0));
 
 
        case 14:
        case 14:
          if (AVR_ENHANCED && ldi_ok)
          if (AVR_ENHANCED && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%B0,0x40) CR_TAB
              return (AS2 (ldi,%B0,0x40) CR_TAB
                      AS2 (mul,%A0,%B0)  CR_TAB
                      AS2 (mul,%A0,%B0)  CR_TAB
                      AS2 (mov,%B0,r0)   CR_TAB
                      AS2 (mov,%B0,r0)   CR_TAB
                      AS1 (clr,%A0)      CR_TAB
                      AS1 (clr,%A0)      CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (AVR_ENHANCED && scratch)
          if (AVR_ENHANCED && scratch)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%3,0x40) CR_TAB
              return (AS2 (ldi,%3,0x40) CR_TAB
                      AS2 (mul,%A0,%3)  CR_TAB
                      AS2 (mul,%A0,%3)  CR_TAB
                      AS2 (mov,%B0,r0)  CR_TAB
                      AS2 (mov,%B0,r0)  CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,%A0)     CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size && ldi_ok)
          if (optimize_size && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (mov,%B0,%A0) CR_TAB
              return (AS2 (mov,%B0,%A0) CR_TAB
                      AS2 (ldi,%A0,6) "\n1:\t"
                      AS2 (ldi,%A0,6) "\n1:\t"
                      AS1 (lsl,%B0)     CR_TAB
                      AS1 (lsl,%B0)     CR_TAB
                      AS1 (dec,%A0)     CR_TAB
                      AS1 (dec,%A0)     CR_TAB
                      AS1 (brne,1b));
                      AS1 (brne,1b));
            }
            }
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          *len = 6;
          *len = 6;
          return (AS1 (clr,%B0) CR_TAB
          return (AS1 (clr,%B0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (ror,%B0) CR_TAB
                  AS1 (ror,%B0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (ror,%B0) CR_TAB
                  AS1 (ror,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
 
 
        case 15:
        case 15:
          *len = 4;
          *len = 4;
          return (AS1 (clr,%B0) CR_TAB
          return (AS1 (clr,%B0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (ror,%B0) CR_TAB
                  AS1 (ror,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
        }
        }
      len = t;
      len = t;
    }
    }
  out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
  out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
                       AS1 (rol,%B0)),
                       AS1 (rol,%B0)),
                       insn, operands, len, 2);
                       insn, operands, len, 2);
  return "";
  return "";
}
}
 
 
 
 
/* 32bit shift left ((long)x << i)   */
/* 32bit shift left ((long)x << i)   */
 
 
const char *
const char *
ashlsi3_out (rtx insn, rtx operands[], int *len)
ashlsi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int k;
      int k;
      int *t = len;
      int *t = len;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        default:
        default:
          if (INTVAL (operands[2]) < 32)
          if (INTVAL (operands[2]) < 32)
            break;
            break;
 
 
          if (AVR_HAVE_MOVW)
          if (AVR_HAVE_MOVW)
            return *len = 3, (AS1 (clr,%D0) CR_TAB
            return *len = 3, (AS1 (clr,%D0) CR_TAB
                              AS1 (clr,%C0) CR_TAB
                              AS1 (clr,%C0) CR_TAB
                              AS2 (movw,%A0,%C0));
                              AS2 (movw,%A0,%C0));
          *len = 4;
          *len = 4;
          return (AS1 (clr,%D0) CR_TAB
          return (AS1 (clr,%D0) CR_TAB
                  AS1 (clr,%C0) CR_TAB
                  AS1 (clr,%C0) CR_TAB
                  AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
 
 
        case 8:
        case 8:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
            *len = 4;
            *len = 4;
            if (reg0 >= reg1)
            if (reg0 >= reg1)
              return (AS2 (mov,%D0,%C1)  CR_TAB
              return (AS2 (mov,%D0,%C1)  CR_TAB
                      AS2 (mov,%C0,%B1)  CR_TAB
                      AS2 (mov,%C0,%B1)  CR_TAB
                      AS2 (mov,%B0,%A1)  CR_TAB
                      AS2 (mov,%B0,%A1)  CR_TAB
                      AS1 (clr,%A0));
                      AS1 (clr,%A0));
            else if (reg0 + 1 == reg1)
            else if (reg0 + 1 == reg1)
              {
              {
                *len = 1;
                *len = 1;
                return AS1 (clr,%A0);
                return AS1 (clr,%A0);
              }
              }
            else
            else
              return (AS1 (clr,%A0)      CR_TAB
              return (AS1 (clr,%A0)      CR_TAB
                      AS2 (mov,%B0,%A1)  CR_TAB
                      AS2 (mov,%B0,%A1)  CR_TAB
                      AS2 (mov,%C0,%B1)  CR_TAB
                      AS2 (mov,%C0,%B1)  CR_TAB
                      AS2 (mov,%D0,%C1));
                      AS2 (mov,%D0,%C1));
          }
          }
 
 
        case 16:
        case 16:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
            *len = 4;
            *len = 4;
            if (AVR_HAVE_MOVW && (reg0 + 2 != reg1))
            if (AVR_HAVE_MOVW && (reg0 + 2 != reg1))
              {
              {
                *len = 3;
                *len = 3;
                return (AS2 (movw,%C0,%A1) CR_TAB
                return (AS2 (movw,%C0,%A1) CR_TAB
                        AS1 (clr,%B0)      CR_TAB
                        AS1 (clr,%B0)      CR_TAB
                        AS1 (clr,%A0));
                        AS1 (clr,%A0));
              }
              }
            if (reg0 + 1 >= reg1)
            if (reg0 + 1 >= reg1)
              return (AS2 (mov,%D0,%B1)  CR_TAB
              return (AS2 (mov,%D0,%B1)  CR_TAB
                      AS2 (mov,%C0,%A1)  CR_TAB
                      AS2 (mov,%C0,%A1)  CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%A0));
                      AS1 (clr,%A0));
            if (reg0 + 2 == reg1)
            if (reg0 + 2 == reg1)
              {
              {
                *len = 2;
                *len = 2;
                return (AS1 (clr,%B0)      CR_TAB
                return (AS1 (clr,%B0)      CR_TAB
                        AS1 (clr,%A0));
                        AS1 (clr,%A0));
              }
              }
            else
            else
              return (AS2 (mov,%C0,%A1)  CR_TAB
              return (AS2 (mov,%C0,%A1)  CR_TAB
                      AS2 (mov,%D0,%B1)  CR_TAB
                      AS2 (mov,%D0,%B1)  CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%A0));
                      AS1 (clr,%A0));
          }
          }
 
 
        case 24:
        case 24:
          *len = 4;
          *len = 4;
          if (true_regnum (operands[0]) + 3 != true_regnum (operands[1]))
          if (true_regnum (operands[0]) + 3 != true_regnum (operands[1]))
            return (AS2 (mov,%D0,%A1)  CR_TAB
            return (AS2 (mov,%D0,%A1)  CR_TAB
                    AS1 (clr,%C0)      CR_TAB
                    AS1 (clr,%C0)      CR_TAB
                    AS1 (clr,%B0)      CR_TAB
                    AS1 (clr,%B0)      CR_TAB
                    AS1 (clr,%A0));
                    AS1 (clr,%A0));
          else
          else
            {
            {
              *len = 3;
              *len = 3;
              return (AS1 (clr,%C0)      CR_TAB
              return (AS1 (clr,%C0)      CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%A0));
                      AS1 (clr,%A0));
            }
            }
 
 
        case 31:
        case 31:
          *len = 6;
          *len = 6;
          return (AS1 (clr,%D0) CR_TAB
          return (AS1 (clr,%D0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (lsr,%A0) CR_TAB
                  AS1 (ror,%D0) CR_TAB
                  AS1 (ror,%D0) CR_TAB
                  AS1 (clr,%C0) CR_TAB
                  AS1 (clr,%C0) CR_TAB
                  AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
        }
        }
      len = t;
      len = t;
    }
    }
  out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
  out_shift_with_cnt ((AS1 (lsl,%A0) CR_TAB
                       AS1 (rol,%B0) CR_TAB
                       AS1 (rol,%B0) CR_TAB
                       AS1 (rol,%C0) CR_TAB
                       AS1 (rol,%C0) CR_TAB
                       AS1 (rol,%D0)),
                       AS1 (rol,%D0)),
                       insn, operands, len, 4);
                       insn, operands, len, 4);
  return "";
  return "";
}
}
 
 
/* 8bit arithmetic shift right  ((signed char)x >> i) */
/* 8bit arithmetic shift right  ((signed char)x >> i) */
 
 
const char *
const char *
ashrqi3_out (rtx insn, rtx operands[], int *len)
ashrqi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int k;
      int k;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        case 1:
        case 1:
          *len = 1;
          *len = 1;
          return AS1 (asr,%0);
          return AS1 (asr,%0);
 
 
        case 2:
        case 2:
          *len = 2;
          *len = 2;
          return (AS1 (asr,%0) CR_TAB
          return (AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0));
                  AS1 (asr,%0));
 
 
        case 3:
        case 3:
          *len = 3;
          *len = 3;
          return (AS1 (asr,%0) CR_TAB
          return (AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0));
                  AS1 (asr,%0));
 
 
        case 4:
        case 4:
          *len = 4;
          *len = 4;
          return (AS1 (asr,%0) CR_TAB
          return (AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0));
                  AS1 (asr,%0));
 
 
        case 5:
        case 5:
          *len = 5;
          *len = 5;
          return (AS1 (asr,%0) CR_TAB
          return (AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0) CR_TAB
                  AS1 (asr,%0));
                  AS1 (asr,%0));
 
 
        case 6:
        case 6:
          *len = 4;
          *len = 4;
          return (AS2 (bst,%0,6)  CR_TAB
          return (AS2 (bst,%0,6)  CR_TAB
                  AS1 (lsl,%0)    CR_TAB
                  AS1 (lsl,%0)    CR_TAB
                  AS2 (sbc,%0,%0) CR_TAB
                  AS2 (sbc,%0,%0) CR_TAB
                  AS2 (bld,%0,0));
                  AS2 (bld,%0,0));
 
 
        default:
        default:
          if (INTVAL (operands[2]) < 8)
          if (INTVAL (operands[2]) < 8)
            break;
            break;
 
 
          /* fall through */
          /* fall through */
 
 
        case 7:
        case 7:
          *len = 2;
          *len = 2;
          return (AS1 (lsl,%0) CR_TAB
          return (AS1 (lsl,%0) CR_TAB
                  AS2 (sbc,%0,%0));
                  AS2 (sbc,%0,%0));
        }
        }
    }
    }
  else if (CONSTANT_P (operands[2]))
  else if (CONSTANT_P (operands[2]))
    fatal_insn ("internal compiler error.  Incorrect shift:", insn);
    fatal_insn ("internal compiler error.  Incorrect shift:", insn);
 
 
  out_shift_with_cnt (AS1 (asr,%0),
  out_shift_with_cnt (AS1 (asr,%0),
                      insn, operands, len, 1);
                      insn, operands, len, 1);
  return "";
  return "";
}
}
 
 
 
 
/* 16bit arithmetic shift right  ((signed short)x >> i) */
/* 16bit arithmetic shift right  ((signed short)x >> i) */
 
 
const char *
const char *
ashrhi3_out (rtx insn, rtx operands[], int *len)
ashrhi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
      int k;
      int k;
      int *t = len;
      int *t = len;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        case 4:
        case 4:
        case 5:
        case 5:
          /* XXX try to optimize this too? */
          /* XXX try to optimize this too? */
          break;
          break;
 
 
        case 6:
        case 6:
          if (optimize_size)
          if (optimize_size)
            break;  /* scratch ? 5 : 6 */
            break;  /* scratch ? 5 : 6 */
          *len = 8;
          *len = 8;
          return (AS2 (mov,__tmp_reg__,%A0) CR_TAB
          return (AS2 (mov,__tmp_reg__,%A0) CR_TAB
                  AS2 (mov,%A0,%B0)         CR_TAB
                  AS2 (mov,%A0,%B0)         CR_TAB
                  AS1 (lsl,__tmp_reg__)     CR_TAB
                  AS1 (lsl,__tmp_reg__)     CR_TAB
                  AS1 (rol,%A0)             CR_TAB
                  AS1 (rol,%A0)             CR_TAB
                  AS2 (sbc,%B0,%B0)         CR_TAB
                  AS2 (sbc,%B0,%B0)         CR_TAB
                  AS1 (lsl,__tmp_reg__)     CR_TAB
                  AS1 (lsl,__tmp_reg__)     CR_TAB
                  AS1 (rol,%A0)             CR_TAB
                  AS1 (rol,%A0)             CR_TAB
                  AS1 (rol,%B0));
                  AS1 (rol,%B0));
 
 
        case 7:
        case 7:
          *len = 4;
          *len = 4;
          return (AS1 (lsl,%A0)     CR_TAB
          return (AS1 (lsl,%A0)     CR_TAB
                  AS2 (mov,%A0,%B0) CR_TAB
                  AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (rol,%A0)     CR_TAB
                  AS1 (rol,%A0)     CR_TAB
                  AS2 (sbc,%B0,%B0));
                  AS2 (sbc,%B0,%B0));
 
 
        case 8:
        case 8:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
 
 
            if (reg0 == reg1)
            if (reg0 == reg1)
              return *len = 3, (AS2 (mov,%A0,%B0) CR_TAB
              return *len = 3, (AS2 (mov,%A0,%B0) CR_TAB
                                AS1 (lsl,%B0)     CR_TAB
                                AS1 (lsl,%B0)     CR_TAB
                                AS2 (sbc,%B0,%B0));
                                AS2 (sbc,%B0,%B0));
            else if (reg0 == reg1 + 1)
            else if (reg0 == reg1 + 1)
              return *len = 3, (AS1 (clr,%B0)    CR_TAB
              return *len = 3, (AS1 (clr,%B0)    CR_TAB
                                AS2 (sbrc,%A0,7) CR_TAB
                                AS2 (sbrc,%A0,7) CR_TAB
                                AS1 (dec,%B0));
                                AS1 (dec,%B0));
 
 
            return *len = 4, (AS2 (mov,%A0,%B1) CR_TAB
            return *len = 4, (AS2 (mov,%A0,%B1) CR_TAB
                              AS1 (clr,%B0)     CR_TAB
                              AS1 (clr,%B0)     CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS1 (dec,%B0));
                              AS1 (dec,%B0));
          }
          }
 
 
        case 9:
        case 9:
          *len = 4;
          *len = 4;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (lsl,%B0)      CR_TAB
                  AS1 (lsl,%B0)      CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS1 (asr,%A0));
                  AS1 (asr,%A0));
 
 
        case 10:
        case 10:
          *len = 5;
          *len = 5;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0));
                  AS1 (asr,%A0));
 
 
        case 11:
        case 11:
          if (AVR_ENHANCED && ldi_ok)
          if (AVR_ENHANCED && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%A0,0x20) CR_TAB
              return (AS2 (ldi,%A0,0x20) CR_TAB
                      AS2 (muls,%B0,%A0) CR_TAB
                      AS2 (muls,%B0,%A0) CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (sbc,%B0,%B0)  CR_TAB
                      AS2 (sbc,%B0,%B0)  CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          *len = 6;
          *len = 6;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0));
                  AS1 (asr,%A0));
 
 
        case 12:
        case 12:
          if (AVR_ENHANCED && ldi_ok)
          if (AVR_ENHANCED && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%A0,0x10) CR_TAB
              return (AS2 (ldi,%A0,0x10) CR_TAB
                      AS2 (muls,%B0,%A0) CR_TAB
                      AS2 (muls,%B0,%A0) CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (sbc,%B0,%B0)  CR_TAB
                      AS2 (sbc,%B0,%B0)  CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          *len = 7;
          *len = 7;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0));
                  AS1 (asr,%A0));
 
 
        case 13:
        case 13:
          if (AVR_ENHANCED && ldi_ok)
          if (AVR_ENHANCED && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%A0,0x08) CR_TAB
              return (AS2 (ldi,%A0,0x08) CR_TAB
                      AS2 (muls,%B0,%A0) CR_TAB
                      AS2 (muls,%B0,%A0) CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (sbc,%B0,%B0)  CR_TAB
                      AS2 (sbc,%B0,%B0)  CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size)
          if (optimize_size)
            break;  /* scratch ? 5 : 7 */
            break;  /* scratch ? 5 : 7 */
          *len = 8;
          *len = 8;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0)     CR_TAB
                  AS1 (asr,%A0));
                  AS1 (asr,%A0));
 
 
        case 14:
        case 14:
          *len = 5;
          *len = 5;
          return (AS1 (lsl,%B0)     CR_TAB
          return (AS1 (lsl,%B0)     CR_TAB
                  AS2 (sbc,%A0,%A0) CR_TAB
                  AS2 (sbc,%A0,%A0) CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS1 (lsl,%B0)     CR_TAB
                  AS2 (mov,%B0,%A0) CR_TAB
                  AS2 (mov,%B0,%A0) CR_TAB
                  AS1 (rol,%A0));
                  AS1 (rol,%A0));
 
 
        default:
        default:
          if (INTVAL (operands[2]) < 16)
          if (INTVAL (operands[2]) < 16)
            break;
            break;
 
 
          /* fall through */
          /* fall through */
 
 
        case 15:
        case 15:
          return *len = 3, (AS1 (lsl,%B0)     CR_TAB
          return *len = 3, (AS1 (lsl,%B0)     CR_TAB
                            AS2 (sbc,%A0,%A0) CR_TAB
                            AS2 (sbc,%A0,%A0) CR_TAB
                            AS2 (mov,%B0,%A0));
                            AS2 (mov,%B0,%A0));
        }
        }
      len = t;
      len = t;
    }
    }
  out_shift_with_cnt ((AS1 (asr,%B0) CR_TAB
  out_shift_with_cnt ((AS1 (asr,%B0) CR_TAB
                       AS1 (ror,%A0)),
                       AS1 (ror,%A0)),
                       insn, operands, len, 2);
                       insn, operands, len, 2);
  return "";
  return "";
}
}
 
 
 
 
/* 32bit arithmetic shift right  ((signed long)x >> i) */
/* 32bit arithmetic shift right  ((signed long)x >> i) */
 
 
const char *
const char *
ashrsi3_out (rtx insn, rtx operands[], int *len)
ashrsi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int k;
      int k;
      int *t = len;
      int *t = len;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        case 8:
        case 8:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
            *len=6;
            *len=6;
            if (reg0 <= reg1)
            if (reg0 <= reg1)
              return (AS2 (mov,%A0,%B1) CR_TAB
              return (AS2 (mov,%A0,%B1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS1 (clr,%D0)     CR_TAB
                      AS1 (clr,%D0)     CR_TAB
                      AS2 (sbrc,%C0,7)  CR_TAB
                      AS2 (sbrc,%C0,7)  CR_TAB
                      AS1 (dec,%D0));
                      AS1 (dec,%D0));
            else if (reg0 == reg1 + 1)
            else if (reg0 == reg1 + 1)
              {
              {
                *len = 3;
                *len = 3;
                return (AS1 (clr,%D0)     CR_TAB
                return (AS1 (clr,%D0)     CR_TAB
                        AS2 (sbrc,%C0,7)  CR_TAB
                        AS2 (sbrc,%C0,7)  CR_TAB
                        AS1 (dec,%D0));
                        AS1 (dec,%D0));
              }
              }
            else
            else
              return (AS1 (clr,%D0)     CR_TAB
              return (AS1 (clr,%D0)     CR_TAB
                      AS2 (sbrc,%D1,7)  CR_TAB
                      AS2 (sbrc,%D1,7)  CR_TAB
                      AS1 (dec,%D0)     CR_TAB
                      AS1 (dec,%D0)     CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%A0,%B1));
                      AS2 (mov,%A0,%B1));
          }
          }
 
 
        case 16:
        case 16:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
            *len=6;
            *len=6;
            if (AVR_HAVE_MOVW && (reg0 != reg1 + 2))
            if (AVR_HAVE_MOVW && (reg0 != reg1 + 2))
              {
              {
                *len = 5;
                *len = 5;
                return (AS2 (movw,%A0,%C1) CR_TAB
                return (AS2 (movw,%A0,%C1) CR_TAB
                        AS1 (clr,%D0)      CR_TAB
                        AS1 (clr,%D0)      CR_TAB
                        AS2 (sbrc,%B0,7)   CR_TAB
                        AS2 (sbrc,%B0,7)   CR_TAB
                        AS1 (com,%D0)      CR_TAB
                        AS1 (com,%D0)      CR_TAB
                        AS2 (mov,%C0,%D0));
                        AS2 (mov,%C0,%D0));
              }
              }
            if (reg0 <= reg1 + 1)
            if (reg0 <= reg1 + 1)
              return (AS2 (mov,%A0,%C1) CR_TAB
              return (AS2 (mov,%A0,%C1) CR_TAB
                      AS2 (mov,%B0,%D1) CR_TAB
                      AS2 (mov,%B0,%D1) CR_TAB
                      AS1 (clr,%D0)     CR_TAB
                      AS1 (clr,%D0)     CR_TAB
                      AS2 (sbrc,%B0,7)  CR_TAB
                      AS2 (sbrc,%B0,7)  CR_TAB
                      AS1 (com,%D0)     CR_TAB
                      AS1 (com,%D0)     CR_TAB
                      AS2 (mov,%C0,%D0));
                      AS2 (mov,%C0,%D0));
            else if (reg0 == reg1 + 2)
            else if (reg0 == reg1 + 2)
              return *len = 4, (AS1 (clr,%D0)     CR_TAB
              return *len = 4, (AS1 (clr,%D0)     CR_TAB
                                AS2 (sbrc,%B0,7)  CR_TAB
                                AS2 (sbrc,%B0,7)  CR_TAB
                                AS1 (com,%D0)     CR_TAB
                                AS1 (com,%D0)     CR_TAB
                                AS2 (mov,%C0,%D0));
                                AS2 (mov,%C0,%D0));
            else
            else
              return (AS2 (mov,%B0,%D1) CR_TAB
              return (AS2 (mov,%B0,%D1) CR_TAB
                      AS2 (mov,%A0,%C1) CR_TAB
                      AS2 (mov,%A0,%C1) CR_TAB
                      AS1 (clr,%D0)     CR_TAB
                      AS1 (clr,%D0)     CR_TAB
                      AS2 (sbrc,%B0,7)  CR_TAB
                      AS2 (sbrc,%B0,7)  CR_TAB
                      AS1 (com,%D0)     CR_TAB
                      AS1 (com,%D0)     CR_TAB
                      AS2 (mov,%C0,%D0));
                      AS2 (mov,%C0,%D0));
          }
          }
 
 
        case 24:
        case 24:
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
            return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
            return *len = 6, (AS2 (mov,%A0,%D1) CR_TAB
                              AS1 (clr,%D0)     CR_TAB
                              AS1 (clr,%D0)     CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS1 (com,%D0)     CR_TAB
                              AS1 (com,%D0)     CR_TAB
                              AS2 (mov,%B0,%D0) CR_TAB
                              AS2 (mov,%B0,%D0) CR_TAB
                              AS2 (mov,%C0,%D0));
                              AS2 (mov,%C0,%D0));
          else
          else
            return *len = 5, (AS1 (clr,%D0)     CR_TAB
            return *len = 5, (AS1 (clr,%D0)     CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS2 (sbrc,%A0,7)  CR_TAB
                              AS1 (com,%D0)     CR_TAB
                              AS1 (com,%D0)     CR_TAB
                              AS2 (mov,%B0,%D0) CR_TAB
                              AS2 (mov,%B0,%D0) CR_TAB
                              AS2 (mov,%C0,%D0));
                              AS2 (mov,%C0,%D0));
 
 
        default:
        default:
          if (INTVAL (operands[2]) < 32)
          if (INTVAL (operands[2]) < 32)
            break;
            break;
 
 
          /* fall through */
          /* fall through */
 
 
        case 31:
        case 31:
          if (AVR_HAVE_MOVW)
          if (AVR_HAVE_MOVW)
            return *len = 4, (AS1 (lsl,%D0)     CR_TAB
            return *len = 4, (AS1 (lsl,%D0)     CR_TAB
                              AS2 (sbc,%A0,%A0) CR_TAB
                              AS2 (sbc,%A0,%A0) CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
                              AS2 (movw,%C0,%A0));
                              AS2 (movw,%C0,%A0));
          else
          else
            return *len = 5, (AS1 (lsl,%D0)     CR_TAB
            return *len = 5, (AS1 (lsl,%D0)     CR_TAB
                              AS2 (sbc,%A0,%A0) CR_TAB
                              AS2 (sbc,%A0,%A0) CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
                              AS2 (mov,%B0,%A0) CR_TAB
                              AS2 (mov,%C0,%A0) CR_TAB
                              AS2 (mov,%C0,%A0) CR_TAB
                              AS2 (mov,%D0,%A0));
                              AS2 (mov,%D0,%A0));
        }
        }
      len = t;
      len = t;
    }
    }
  out_shift_with_cnt ((AS1 (asr,%D0) CR_TAB
  out_shift_with_cnt ((AS1 (asr,%D0) CR_TAB
                       AS1 (ror,%C0) CR_TAB
                       AS1 (ror,%C0) CR_TAB
                       AS1 (ror,%B0) CR_TAB
                       AS1 (ror,%B0) CR_TAB
                       AS1 (ror,%A0)),
                       AS1 (ror,%A0)),
                       insn, operands, len, 4);
                       insn, operands, len, 4);
  return "";
  return "";
}
}
 
 
/* 8bit logic shift right ((unsigned char)x >> i) */
/* 8bit logic shift right ((unsigned char)x >> i) */
 
 
const char *
const char *
lshrqi3_out (rtx insn, rtx operands[], int *len)
lshrqi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int k;
      int k;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        default:
        default:
          if (INTVAL (operands[2]) < 8)
          if (INTVAL (operands[2]) < 8)
            break;
            break;
 
 
          *len = 1;
          *len = 1;
          return AS1 (clr,%0);
          return AS1 (clr,%0);
 
 
        case 1:
        case 1:
          *len = 1;
          *len = 1;
          return AS1 (lsr,%0);
          return AS1 (lsr,%0);
 
 
        case 2:
        case 2:
          *len = 2;
          *len = 2;
          return (AS1 (lsr,%0) CR_TAB
          return (AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0));
                  AS1 (lsr,%0));
        case 3:
        case 3:
          *len = 3;
          *len = 3;
          return (AS1 (lsr,%0) CR_TAB
          return (AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0));
                  AS1 (lsr,%0));
 
 
        case 4:
        case 4:
          if (test_hard_reg_class (LD_REGS, operands[0]))
          if (test_hard_reg_class (LD_REGS, operands[0]))
            {
            {
              *len=2;
              *len=2;
              return (AS1 (swap,%0) CR_TAB
              return (AS1 (swap,%0) CR_TAB
                      AS2 (andi,%0,0x0f));
                      AS2 (andi,%0,0x0f));
            }
            }
          *len = 4;
          *len = 4;
          return (AS1 (lsr,%0) CR_TAB
          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));
                  AS1 (lsr,%0));
 
 
        case 5:
        case 5:
          if (test_hard_reg_class (LD_REGS, operands[0]))
          if (test_hard_reg_class (LD_REGS, operands[0]))
            {
            {
              *len = 3;
              *len = 3;
              return (AS1 (swap,%0) CR_TAB
              return (AS1 (swap,%0) CR_TAB
                      AS1 (lsr,%0)  CR_TAB
                      AS1 (lsr,%0)  CR_TAB
                      AS2 (andi,%0,0x7));
                      AS2 (andi,%0,0x7));
            }
            }
          *len = 5;
          *len = 5;
          return (AS1 (lsr,%0) CR_TAB
          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) CR_TAB
                  AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0));
                  AS1 (lsr,%0));
 
 
        case 6:
        case 6:
          if (test_hard_reg_class (LD_REGS, operands[0]))
          if (test_hard_reg_class (LD_REGS, operands[0]))
            {
            {
              *len = 4;
              *len = 4;
              return (AS1 (swap,%0) CR_TAB
              return (AS1 (swap,%0) CR_TAB
                      AS1 (lsr,%0)  CR_TAB
                      AS1 (lsr,%0)  CR_TAB
                      AS1 (lsr,%0)  CR_TAB
                      AS1 (lsr,%0)  CR_TAB
                      AS2 (andi,%0,0x3));
                      AS2 (andi,%0,0x3));
            }
            }
          *len = 6;
          *len = 6;
          return (AS1 (lsr,%0) CR_TAB
          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) CR_TAB
                  AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0) CR_TAB
                  AS1 (lsr,%0));
                  AS1 (lsr,%0));
 
 
        case 7:
        case 7:
          *len = 3;
          *len = 3;
          return (AS1 (rol,%0) CR_TAB
          return (AS1 (rol,%0) CR_TAB
                  AS1 (clr,%0) CR_TAB
                  AS1 (clr,%0) CR_TAB
                  AS1 (rol,%0));
                  AS1 (rol,%0));
        }
        }
    }
    }
  else if (CONSTANT_P (operands[2]))
  else if (CONSTANT_P (operands[2]))
    fatal_insn ("internal compiler error.  Incorrect shift:", insn);
    fatal_insn ("internal compiler error.  Incorrect shift:", insn);
 
 
  out_shift_with_cnt (AS1 (lsr,%0),
  out_shift_with_cnt (AS1 (lsr,%0),
                      insn, operands, len, 1);
                      insn, operands, len, 1);
  return "";
  return "";
}
}
 
 
/* 16bit logic shift right ((unsigned short)x >> i) */
/* 16bit logic shift right ((unsigned short)x >> i) */
 
 
const char *
const char *
lshrhi3_out (rtx insn, rtx operands[], int *len)
lshrhi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int scratch = (GET_CODE (PATTERN (insn)) == PARALLEL);
      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
      int ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
      int k;
      int k;
      int *t = len;
      int *t = len;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        default:
        default:
          if (INTVAL (operands[2]) < 16)
          if (INTVAL (operands[2]) < 16)
            break;
            break;
 
 
          *len = 2;
          *len = 2;
          return (AS1 (clr,%B0) CR_TAB
          return (AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
 
 
        case 4:
        case 4:
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 6;
              *len = 6;
              return (AS1 (swap,%B0)      CR_TAB
              return (AS1 (swap,%B0)      CR_TAB
                      AS1 (swap,%A0)      CR_TAB
                      AS1 (swap,%A0)      CR_TAB
                      AS2 (andi,%A0,0x0f) CR_TAB
                      AS2 (andi,%A0,0x0f) CR_TAB
                      AS2 (eor,%A0,%B0)   CR_TAB
                      AS2 (eor,%A0,%B0)   CR_TAB
                      AS2 (andi,%B0,0x0f) CR_TAB
                      AS2 (andi,%B0,0x0f) CR_TAB
                      AS2 (eor,%A0,%B0));
                      AS2 (eor,%A0,%B0));
            }
            }
          if (scratch)
          if (scratch)
            {
            {
              *len = 7;
              *len = 7;
              return (AS1 (swap,%B0)    CR_TAB
              return (AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS2 (ldi,%3,0x0f) CR_TAB
                      AS2 (ldi,%3,0x0f) CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (eor,%A0,%B0) CR_TAB
                      AS2 (eor,%A0,%B0) CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (eor,%A0,%B0));
                      AS2 (eor,%A0,%B0));
            }
            }
          break;  /* optimize_size ? 6 : 8 */
          break;  /* optimize_size ? 6 : 8 */
 
 
        case 5:
        case 5:
          if (optimize_size)
          if (optimize_size)
            break;  /* scratch ? 5 : 6 */
            break;  /* scratch ? 5 : 6 */
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 8;
              *len = 8;
              return (AS1 (lsr,%B0)       CR_TAB
              return (AS1 (lsr,%B0)       CR_TAB
                      AS1 (ror,%A0)       CR_TAB
                      AS1 (ror,%A0)       CR_TAB
                      AS1 (swap,%B0)      CR_TAB
                      AS1 (swap,%B0)      CR_TAB
                      AS1 (swap,%A0)      CR_TAB
                      AS1 (swap,%A0)      CR_TAB
                      AS2 (andi,%A0,0x0f) CR_TAB
                      AS2 (andi,%A0,0x0f) CR_TAB
                      AS2 (eor,%A0,%B0)   CR_TAB
                      AS2 (eor,%A0,%B0)   CR_TAB
                      AS2 (andi,%B0,0x0f) CR_TAB
                      AS2 (andi,%B0,0x0f) CR_TAB
                      AS2 (eor,%A0,%B0));
                      AS2 (eor,%A0,%B0));
            }
            }
          if (scratch)
          if (scratch)
            {
            {
              *len = 9;
              *len = 9;
              return (AS1 (lsr,%B0)     CR_TAB
              return (AS1 (lsr,%B0)     CR_TAB
                      AS1 (ror,%A0)     CR_TAB
                      AS1 (ror,%A0)     CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%B0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS2 (ldi,%3,0x0f) CR_TAB
                      AS2 (ldi,%3,0x0f) CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (and,%A0,%3)  CR_TAB
                      AS2 (eor,%A0,%B0) CR_TAB
                      AS2 (eor,%A0,%B0) CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (and,%B0,%3)  CR_TAB
                      AS2 (eor,%A0,%B0));
                      AS2 (eor,%A0,%B0));
            }
            }
          break;  /* 10 */
          break;  /* 10 */
 
 
        case 6:
        case 6:
          if (optimize_size)
          if (optimize_size)
            break;  /* scratch ? 5 : 6 */
            break;  /* scratch ? 5 : 6 */
          *len = 9;
          *len = 9;
          return (AS1 (clr,__tmp_reg__) CR_TAB
          return (AS1 (clr,__tmp_reg__) CR_TAB
                  AS1 (lsl,%A0)         CR_TAB
                  AS1 (lsl,%A0)         CR_TAB
                  AS1 (rol,%B0)         CR_TAB
                  AS1 (rol,%B0)         CR_TAB
                  AS1 (rol,__tmp_reg__) CR_TAB
                  AS1 (rol,__tmp_reg__) CR_TAB
                  AS1 (lsl,%A0)         CR_TAB
                  AS1 (lsl,%A0)         CR_TAB
                  AS1 (rol,%B0)         CR_TAB
                  AS1 (rol,%B0)         CR_TAB
                  AS1 (rol,__tmp_reg__) CR_TAB
                  AS1 (rol,__tmp_reg__) CR_TAB
                  AS2 (mov,%A0,%B0)     CR_TAB
                  AS2 (mov,%A0,%B0)     CR_TAB
                  AS2 (mov,%B0,__tmp_reg__));
                  AS2 (mov,%B0,__tmp_reg__));
 
 
        case 7:
        case 7:
          *len = 5;
          *len = 5;
          return (AS1 (lsl,%A0)     CR_TAB
          return (AS1 (lsl,%A0)     CR_TAB
                  AS2 (mov,%A0,%B0) CR_TAB
                  AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (rol,%A0)     CR_TAB
                  AS1 (rol,%A0)     CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS2 (sbc,%B0,%B0) CR_TAB
                  AS1 (neg,%B0));
                  AS1 (neg,%B0));
 
 
        case 8:
        case 8:
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 1)
            return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
            return *len = 2, (AS2 (mov,%A0,%B1) CR_TAB
                              AS1 (clr,%B0));
                              AS1 (clr,%B0));
          else
          else
            return *len = 1, AS1 (clr,%B0);
            return *len = 1, AS1 (clr,%B0);
 
 
        case 9:
        case 9:
          *len = 3;
          *len = 3;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (lsr,%A0));
                  AS1 (lsr,%A0));
 
 
        case 10:
        case 10:
          *len = 4;
          *len = 4;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0));
                  AS1 (lsr,%A0));
 
 
        case 11:
        case 11:
          *len = 5;
          *len = 5;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0));
                  AS1 (lsr,%A0));
 
 
        case 12:
        case 12:
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 4;
              *len = 4;
              return (AS2 (mov,%A0,%B0) CR_TAB
              return (AS2 (mov,%A0,%B0) CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS2 (andi,%A0,0x0f));
                      AS2 (andi,%A0,0x0f));
            }
            }
          if (scratch)
          if (scratch)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (mov,%A0,%B0) CR_TAB
              return (AS2 (mov,%A0,%B0) CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS2 (ldi,%3,0x0f) CR_TAB
                      AS2 (ldi,%3,0x0f) CR_TAB
                      AS2 (and,%A0,%3));
                      AS2 (and,%A0,%3));
            }
            }
          *len = 6;
          *len = 6;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0));
                  AS1 (lsr,%A0));
 
 
        case 13:
        case 13:
          if (ldi_ok)
          if (ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (mov,%A0,%B0) CR_TAB
              return (AS2 (mov,%A0,%B0) CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (lsr,%A0)     CR_TAB
                      AS1 (lsr,%A0)     CR_TAB
                      AS2 (andi,%A0,0x07));
                      AS2 (andi,%A0,0x07));
            }
            }
          if (AVR_ENHANCED && scratch)
          if (AVR_ENHANCED && scratch)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%3,0x08) CR_TAB
              return (AS2 (ldi,%3,0x08) CR_TAB
                      AS2 (mul,%B0,%3)  CR_TAB
                      AS2 (mul,%B0,%3)  CR_TAB
                      AS2 (mov,%A0,r1)  CR_TAB
                      AS2 (mov,%A0,r1)  CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          if (scratch)
          if (scratch)
            {
            {
              *len = 6;
              *len = 6;
              return (AS2 (mov,%A0,%B0) CR_TAB
              return (AS2 (mov,%A0,%B0) CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (swap,%A0)    CR_TAB
                      AS1 (lsr,%A0)     CR_TAB
                      AS1 (lsr,%A0)     CR_TAB
                      AS2 (ldi,%3,0x07) CR_TAB
                      AS2 (ldi,%3,0x07) CR_TAB
                      AS2 (and,%A0,%3));
                      AS2 (and,%A0,%3));
            }
            }
          if (AVR_ENHANCED)
          if (AVR_ENHANCED)
            {
            {
              *len = 6;
              *len = 6;
              return ("set"            CR_TAB
              return ("set"            CR_TAB
                      AS2 (bld,r1,3)   CR_TAB
                      AS2 (bld,r1,3)   CR_TAB
                      AS2 (mul,%B0,r1) CR_TAB
                      AS2 (mul,%B0,r1) CR_TAB
                      AS2 (mov,%A0,r1) CR_TAB
                      AS2 (mov,%A0,r1) CR_TAB
                      AS1 (clr,%B0)    CR_TAB
                      AS1 (clr,%B0)    CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          *len = 7;
          *len = 7;
          return (AS2 (mov,%A0,%B0) CR_TAB
          return (AS2 (mov,%A0,%B0) CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (clr,%B0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0)     CR_TAB
                  AS1 (lsr,%A0));
                  AS1 (lsr,%A0));
 
 
        case 14:
        case 14:
          if (AVR_ENHANCED && ldi_ok)
          if (AVR_ENHANCED && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%A0,0x04) CR_TAB
              return (AS2 (ldi,%A0,0x04) CR_TAB
                      AS2 (mul,%B0,%A0)  CR_TAB
                      AS2 (mul,%B0,%A0)  CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS2 (mov,%A0,r1)   CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,%B0)      CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (AVR_ENHANCED && scratch)
          if (AVR_ENHANCED && scratch)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (ldi,%3,0x04) CR_TAB
              return (AS2 (ldi,%3,0x04) CR_TAB
                      AS2 (mul,%B0,%3)  CR_TAB
                      AS2 (mul,%B0,%3)  CR_TAB
                      AS2 (mov,%A0,r1)  CR_TAB
                      AS2 (mov,%A0,r1)  CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,%B0)     CR_TAB
                      AS1 (clr,__zero_reg__));
                      AS1 (clr,__zero_reg__));
            }
            }
          if (optimize_size && ldi_ok)
          if (optimize_size && ldi_ok)
            {
            {
              *len = 5;
              *len = 5;
              return (AS2 (mov,%A0,%B0) CR_TAB
              return (AS2 (mov,%A0,%B0) CR_TAB
                      AS2 (ldi,%B0,6) "\n1:\t"
                      AS2 (ldi,%B0,6) "\n1:\t"
                      AS1 (lsr,%A0)     CR_TAB
                      AS1 (lsr,%A0)     CR_TAB
                      AS1 (dec,%B0)     CR_TAB
                      AS1 (dec,%B0)     CR_TAB
                      AS1 (brne,1b));
                      AS1 (brne,1b));
            }
            }
          if (optimize_size && scratch)
          if (optimize_size && scratch)
            break;  /* 5 */
            break;  /* 5 */
          *len = 6;
          *len = 6;
          return (AS1 (clr,%A0) CR_TAB
          return (AS1 (clr,%A0) CR_TAB
                  AS1 (lsl,%B0) CR_TAB
                  AS1 (lsl,%B0) CR_TAB
                  AS1 (rol,%A0) CR_TAB
                  AS1 (rol,%A0) CR_TAB
                  AS1 (lsl,%B0) CR_TAB
                  AS1 (lsl,%B0) CR_TAB
                  AS1 (rol,%A0) CR_TAB
                  AS1 (rol,%A0) CR_TAB
                  AS1 (clr,%B0));
                  AS1 (clr,%B0));
 
 
        case 15:
        case 15:
          *len = 4;
          *len = 4;
          return (AS1 (clr,%A0) CR_TAB
          return (AS1 (clr,%A0) CR_TAB
                  AS1 (lsl,%B0) CR_TAB
                  AS1 (lsl,%B0) CR_TAB
                  AS1 (rol,%A0) CR_TAB
                  AS1 (rol,%A0) CR_TAB
                  AS1 (clr,%B0));
                  AS1 (clr,%B0));
        }
        }
      len = t;
      len = t;
    }
    }
  out_shift_with_cnt ((AS1 (lsr,%B0) CR_TAB
  out_shift_with_cnt ((AS1 (lsr,%B0) CR_TAB
                       AS1 (ror,%A0)),
                       AS1 (ror,%A0)),
                       insn, operands, len, 2);
                       insn, operands, len, 2);
  return "";
  return "";
}
}
 
 
/* 32bit logic shift right ((unsigned int)x >> i) */
/* 32bit logic shift right ((unsigned int)x >> i) */
 
 
const char *
const char *
lshrsi3_out (rtx insn, rtx operands[], int *len)
lshrsi3_out (rtx insn, rtx operands[], int *len)
{
{
  if (GET_CODE (operands[2]) == CONST_INT)
  if (GET_CODE (operands[2]) == CONST_INT)
    {
    {
      int k;
      int k;
      int *t = len;
      int *t = len;
 
 
      if (!len)
      if (!len)
        len = &k;
        len = &k;
 
 
      switch (INTVAL (operands[2]))
      switch (INTVAL (operands[2]))
        {
        {
        default:
        default:
          if (INTVAL (operands[2]) < 32)
          if (INTVAL (operands[2]) < 32)
            break;
            break;
 
 
          if (AVR_HAVE_MOVW)
          if (AVR_HAVE_MOVW)
            return *len = 3, (AS1 (clr,%D0) CR_TAB
            return *len = 3, (AS1 (clr,%D0) CR_TAB
                              AS1 (clr,%C0) CR_TAB
                              AS1 (clr,%C0) CR_TAB
                              AS2 (movw,%A0,%C0));
                              AS2 (movw,%A0,%C0));
          *len = 4;
          *len = 4;
          return (AS1 (clr,%D0) CR_TAB
          return (AS1 (clr,%D0) CR_TAB
                  AS1 (clr,%C0) CR_TAB
                  AS1 (clr,%C0) CR_TAB
                  AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%B0) CR_TAB
                  AS1 (clr,%A0));
                  AS1 (clr,%A0));
 
 
        case 8:
        case 8:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
            *len = 4;
            *len = 4;
            if (reg0 <= reg1)
            if (reg0 <= reg1)
              return (AS2 (mov,%A0,%B1) CR_TAB
              return (AS2 (mov,%A0,%B1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS1 (clr,%D0));
                      AS1 (clr,%D0));
            else if (reg0 == reg1 + 1)
            else if (reg0 == reg1 + 1)
              return *len = 1, AS1 (clr,%D0);
              return *len = 1, AS1 (clr,%D0);
            else
            else
              return (AS1 (clr,%D0)     CR_TAB
              return (AS1 (clr,%D0)     CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS2 (mov,%C0,%D1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%B0,%C1) CR_TAB
                      AS2 (mov,%A0,%B1));
                      AS2 (mov,%A0,%B1));
          }
          }
 
 
        case 16:
        case 16:
          {
          {
            int reg0 = true_regnum (operands[0]);
            int reg0 = true_regnum (operands[0]);
            int reg1 = true_regnum (operands[1]);
            int reg1 = true_regnum (operands[1]);
            *len = 4;
            *len = 4;
            if (AVR_HAVE_MOVW && (reg0 != reg1 + 2))
            if (AVR_HAVE_MOVW && (reg0 != reg1 + 2))
              {
              {
                *len = 3;
                *len = 3;
                return (AS2 (movw,%A0,%C1) CR_TAB
                return (AS2 (movw,%A0,%C1) CR_TAB
                        AS1 (clr,%C0)      CR_TAB
                        AS1 (clr,%C0)      CR_TAB
                        AS1 (clr,%D0));
                        AS1 (clr,%D0));
              }
              }
            if (reg0 <= reg1 + 1)
            if (reg0 <= reg1 + 1)
              return (AS2 (mov,%A0,%C1) CR_TAB
              return (AS2 (mov,%A0,%C1) CR_TAB
                      AS2 (mov,%B0,%D1) CR_TAB
                      AS2 (mov,%B0,%D1) CR_TAB
                      AS1 (clr,%C0)     CR_TAB
                      AS1 (clr,%C0)     CR_TAB
                      AS1 (clr,%D0));
                      AS1 (clr,%D0));
            else if (reg0 == reg1 + 2)
            else if (reg0 == reg1 + 2)
              return *len = 2, (AS1 (clr,%C0)     CR_TAB
              return *len = 2, (AS1 (clr,%C0)     CR_TAB
                                AS1 (clr,%D0));
                                AS1 (clr,%D0));
            else
            else
              return (AS2 (mov,%B0,%D1) CR_TAB
              return (AS2 (mov,%B0,%D1) CR_TAB
                      AS2 (mov,%A0,%C1) CR_TAB
                      AS2 (mov,%A0,%C1) CR_TAB
                      AS1 (clr,%C0)     CR_TAB
                      AS1 (clr,%C0)     CR_TAB
                      AS1 (clr,%D0));
                      AS1 (clr,%D0));
          }
          }
 
 
        case 24:
        case 24:
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
          if (true_regnum (operands[0]) != true_regnum (operands[1]) + 3)
            return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
            return *len = 4, (AS2 (mov,%A0,%D1) CR_TAB
                              AS1 (clr,%B0)     CR_TAB
                              AS1 (clr,%B0)     CR_TAB
                              AS1 (clr,%C0)     CR_TAB
                              AS1 (clr,%C0)     CR_TAB
                              AS1 (clr,%D0));
                              AS1 (clr,%D0));
          else
          else
            return *len = 3, (AS1 (clr,%B0)     CR_TAB
            return *len = 3, (AS1 (clr,%B0)     CR_TAB
                              AS1 (clr,%C0)     CR_TAB
                              AS1 (clr,%C0)     CR_TAB
                              AS1 (clr,%D0));
                              AS1 (clr,%D0));
 
 
        case 31:
        case 31:
          *len = 6;
          *len = 6;
          return (AS1 (clr,%A0)    CR_TAB
          return (AS1 (clr,%A0)    CR_TAB
                  AS2 (sbrc,%D0,7) CR_TAB
                  AS2 (sbrc,%D0,7) CR_TAB
                  AS1 (inc,%A0)    CR_TAB
                  AS1 (inc,%A0)    CR_TAB
                  AS1 (clr,%B0)    CR_TAB
                  AS1 (clr,%B0)    CR_TAB
                  AS1 (clr,%C0)    CR_TAB
                  AS1 (clr,%C0)    CR_TAB
                  AS1 (clr,%D0));
                  AS1 (clr,%D0));
        }
        }
      len = t;
      len = t;
    }
    }
  out_shift_with_cnt ((AS1 (lsr,%D0) CR_TAB
  out_shift_with_cnt ((AS1 (lsr,%D0) CR_TAB
                       AS1 (ror,%C0) CR_TAB
                       AS1 (ror,%C0) CR_TAB
                       AS1 (ror,%B0) CR_TAB
                       AS1 (ror,%B0) CR_TAB
                       AS1 (ror,%A0)),
                       AS1 (ror,%A0)),
                      insn, operands, len, 4);
                      insn, operands, len, 4);
  return "";
  return "";
}
}
 
 
/* Modifies the length assigned to instruction INSN
/* Modifies the length assigned to instruction INSN
 LEN is the initially computed length of the insn.  */
 LEN is the initially computed length of the insn.  */
 
 
int
int
adjust_insn_length (rtx insn, int len)
adjust_insn_length (rtx insn, int len)
{
{
  rtx patt = PATTERN (insn);
  rtx patt = PATTERN (insn);
  rtx set;
  rtx set;
 
 
  if (GET_CODE (patt) == SET)
  if (GET_CODE (patt) == SET)
    {
    {
      rtx op[10];
      rtx op[10];
      op[1] = SET_SRC (patt);
      op[1] = SET_SRC (patt);
      op[0] = SET_DEST (patt);
      op[0] = SET_DEST (patt);
      if (general_operand (op[1], VOIDmode)
      if (general_operand (op[1], VOIDmode)
          && general_operand (op[0], VOIDmode))
          && general_operand (op[0], VOIDmode))
        {
        {
          switch (GET_MODE (op[0]))
          switch (GET_MODE (op[0]))
            {
            {
            case QImode:
            case QImode:
              output_movqi (insn, op, &len);
              output_movqi (insn, op, &len);
              break;
              break;
            case HImode:
            case HImode:
              output_movhi (insn, op, &len);
              output_movhi (insn, op, &len);
              break;
              break;
            case SImode:
            case SImode:
            case SFmode:
            case SFmode:
              output_movsisf (insn, op, &len);
              output_movsisf (insn, op, &len);
              break;
              break;
            default:
            default:
              break;
              break;
            }
            }
        }
        }
      else if (op[0] == cc0_rtx && REG_P (op[1]))
      else if (op[0] == cc0_rtx && REG_P (op[1]))
        {
        {
          switch (GET_MODE (op[1]))
          switch (GET_MODE (op[1]))
            {
            {
            case HImode: out_tsthi (insn,&len); break;
            case HImode: out_tsthi (insn,&len); break;
            case SImode: out_tstsi (insn,&len); break;
            case SImode: out_tstsi (insn,&len); break;
            default: break;
            default: break;
            }
            }
        }
        }
      else if (GET_CODE (op[1]) == AND)
      else if (GET_CODE (op[1]) == AND)
        {
        {
          if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
          if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
            {
            {
              HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
              HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
              if (GET_MODE (op[1]) == SImode)
              if (GET_MODE (op[1]) == SImode)
                len = (((mask & 0xff) != 0xff)
                len = (((mask & 0xff) != 0xff)
                       + ((mask & 0xff00) != 0xff00)
                       + ((mask & 0xff00) != 0xff00)
                       + ((mask & 0xff0000L) != 0xff0000L)
                       + ((mask & 0xff0000L) != 0xff0000L)
                       + ((mask & 0xff000000L) != 0xff000000L));
                       + ((mask & 0xff000000L) != 0xff000000L));
              else if (GET_MODE (op[1]) == HImode)
              else if (GET_MODE (op[1]) == HImode)
                len = (((mask & 0xff) != 0xff)
                len = (((mask & 0xff) != 0xff)
                       + ((mask & 0xff00) != 0xff00));
                       + ((mask & 0xff00) != 0xff00));
            }
            }
        }
        }
      else if (GET_CODE (op[1]) == IOR)
      else if (GET_CODE (op[1]) == IOR)
        {
        {
          if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
          if (GET_CODE (XEXP (op[1],1)) == CONST_INT)
            {
            {
              HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
              HOST_WIDE_INT mask = INTVAL (XEXP (op[1],1));
              if (GET_MODE (op[1]) == SImode)
              if (GET_MODE (op[1]) == SImode)
                len = (((mask & 0xff) != 0)
                len = (((mask & 0xff) != 0)
                       + ((mask & 0xff00) != 0)
                       + ((mask & 0xff00) != 0)
                       + ((mask & 0xff0000L) != 0)
                       + ((mask & 0xff0000L) != 0)
                       + ((mask & 0xff000000L) != 0));
                       + ((mask & 0xff000000L) != 0));
              else if (GET_MODE (op[1]) == HImode)
              else if (GET_MODE (op[1]) == HImode)
                len = (((mask & 0xff) != 0)
                len = (((mask & 0xff) != 0)
                       + ((mask & 0xff00) != 0));
                       + ((mask & 0xff00) != 0));
            }
            }
        }
        }
    }
    }
  set = single_set (insn);
  set = single_set (insn);
  if (set)
  if (set)
    {
    {
      rtx op[10];
      rtx op[10];
 
 
      op[1] = SET_SRC (set);
      op[1] = SET_SRC (set);
      op[0] = SET_DEST (set);
      op[0] = SET_DEST (set);
 
 
      if (GET_CODE (patt) == PARALLEL
      if (GET_CODE (patt) == PARALLEL
          && general_operand (op[1], VOIDmode)
          && general_operand (op[1], VOIDmode)
          && general_operand (op[0], VOIDmode))
          && general_operand (op[0], VOIDmode))
        {
        {
          if (XVECLEN (patt, 0) == 2)
          if (XVECLEN (patt, 0) == 2)
            op[2] = XVECEXP (patt, 0, 1);
            op[2] = XVECEXP (patt, 0, 1);
 
 
          switch (GET_MODE (op[0]))
          switch (GET_MODE (op[0]))
            {
            {
            case QImode:
            case QImode:
              len = 2;
              len = 2;
              break;
              break;
            case HImode:
            case HImode:
              output_reload_inhi (insn, op, &len);
              output_reload_inhi (insn, op, &len);
              break;
              break;
            case SImode:
            case SImode:
            case SFmode:
            case SFmode:
              output_reload_insisf (insn, op, &len);
              output_reload_insisf (insn, op, &len);
              break;
              break;
            default:
            default:
              break;
              break;
            }
            }
        }
        }
      else if (GET_CODE (op[1]) == ASHIFT
      else if (GET_CODE (op[1]) == ASHIFT
          || GET_CODE (op[1]) == ASHIFTRT
          || GET_CODE (op[1]) == ASHIFTRT
          || GET_CODE (op[1]) == LSHIFTRT)
          || GET_CODE (op[1]) == LSHIFTRT)
        {
        {
          rtx ops[10];
          rtx ops[10];
          ops[0] = op[0];
          ops[0] = op[0];
          ops[1] = XEXP (op[1],0);
          ops[1] = XEXP (op[1],0);
          ops[2] = XEXP (op[1],1);
          ops[2] = XEXP (op[1],1);
          switch (GET_CODE (op[1]))
          switch (GET_CODE (op[1]))
            {
            {
            case ASHIFT:
            case ASHIFT:
              switch (GET_MODE (op[0]))
              switch (GET_MODE (op[0]))
                {
                {
                case QImode: ashlqi3_out (insn,ops,&len); break;
                case QImode: ashlqi3_out (insn,ops,&len); break;
                case HImode: ashlhi3_out (insn,ops,&len); break;
                case HImode: ashlhi3_out (insn,ops,&len); break;
                case SImode: ashlsi3_out (insn,ops,&len); break;
                case SImode: ashlsi3_out (insn,ops,&len); break;
                default: break;
                default: break;
                }
                }
              break;
              break;
            case ASHIFTRT:
            case ASHIFTRT:
              switch (GET_MODE (op[0]))
              switch (GET_MODE (op[0]))
                {
                {
                case QImode: ashrqi3_out (insn,ops,&len); break;
                case QImode: ashrqi3_out (insn,ops,&len); break;
                case HImode: ashrhi3_out (insn,ops,&len); break;
                case HImode: ashrhi3_out (insn,ops,&len); break;
                case SImode: ashrsi3_out (insn,ops,&len); break;
                case SImode: ashrsi3_out (insn,ops,&len); break;
                default: break;
                default: break;
                }
                }
              break;
              break;
            case LSHIFTRT:
            case LSHIFTRT:
              switch (GET_MODE (op[0]))
              switch (GET_MODE (op[0]))
                {
                {
                case QImode: lshrqi3_out (insn,ops,&len); break;
                case QImode: lshrqi3_out (insn,ops,&len); break;
                case HImode: lshrhi3_out (insn,ops,&len); break;
                case HImode: lshrhi3_out (insn,ops,&len); break;
                case SImode: lshrsi3_out (insn,ops,&len); break;
                case SImode: lshrsi3_out (insn,ops,&len); break;
                default: break;
                default: break;
                }
                }
              break;
              break;
            default:
            default:
              break;
              break;
            }
            }
        }
        }
    }
    }
  return len;
  return len;
}
}
 
 
/* Return nonzero if register REG dead after INSN.  */
/* Return nonzero if register REG dead after INSN.  */
 
 
int
int
reg_unused_after (rtx insn, rtx reg)
reg_unused_after (rtx insn, rtx reg)
{
{
  return (dead_or_set_p (insn, reg)
  return (dead_or_set_p (insn, reg)
          || (REG_P(reg) && _reg_unused_after (insn, reg)));
          || (REG_P(reg) && _reg_unused_after (insn, reg)));
}
}
 
 
/* Return nonzero if REG is not used after INSN.
/* Return nonzero if REG is not used after INSN.
   We assume REG is a reload reg, and therefore does
   We assume REG is a reload reg, and therefore does
   not live past labels.  It may live past calls or jumps though.  */
   not live past labels.  It may live past calls or jumps though.  */
 
 
int
int
_reg_unused_after (rtx insn, rtx reg)
_reg_unused_after (rtx insn, rtx reg)
{
{
  enum rtx_code code;
  enum rtx_code code;
  rtx set;
  rtx set;
 
 
  /* If the reg is set by this instruction, then it is safe for our
  /* 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
     case.  Disregard the case where this is a store to memory, since
     we are checking a register used in the store address.  */
     we are checking a register used in the store address.  */
  set = single_set (insn);
  set = single_set (insn);
  if (set && GET_CODE (SET_DEST (set)) != MEM
  if (set && GET_CODE (SET_DEST (set)) != MEM
      && reg_overlap_mentioned_p (reg, SET_DEST (set)))
      && reg_overlap_mentioned_p (reg, SET_DEST (set)))
    return 1;
    return 1;
 
 
  while ((insn = NEXT_INSN (insn)))
  while ((insn = NEXT_INSN (insn)))
    {
    {
      rtx set;
      rtx set;
      code = GET_CODE (insn);
      code = GET_CODE (insn);
 
 
#if 0
#if 0
      /* If this is a label that existed before reload, then the register
      /* 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
         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,
         the register may still be live here.  We can't tell the difference,
         so we just ignore labels completely.  */
         so we just ignore labels completely.  */
      if (code == CODE_LABEL)
      if (code == CODE_LABEL)
        return 1;
        return 1;
      /* else */
      /* else */
#endif
#endif
 
 
      if (!INSN_P (insn))
      if (!INSN_P (insn))
        continue;
        continue;
 
 
      if (code == JUMP_INSN)
      if (code == JUMP_INSN)
        return 0;
        return 0;
 
 
      /* If this is a sequence, we must handle them all at once.
      /* If this is a sequence, we must handle them all at once.
         We could have for instance a call that sets the target register,
         We could have for instance a call that sets the target register,
         and an insn in a delay slot that uses the register.  In this case,
         and an insn in a delay slot that uses the register.  In this case,
         we must return 0.  */
         we must return 0.  */
      else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
      else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
        {
        {
          int i;
          int i;
          int retval = 0;
          int retval = 0;
 
 
          for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
          for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
            {
            {
              rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
              rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
              rtx set = single_set (this_insn);
              rtx set = single_set (this_insn);
 
 
              if (GET_CODE (this_insn) == CALL_INSN)
              if (GET_CODE (this_insn) == CALL_INSN)
                code = CALL_INSN;
                code = CALL_INSN;
              else if (GET_CODE (this_insn) == JUMP_INSN)
              else if (GET_CODE (this_insn) == JUMP_INSN)
                {
                {
                  if (INSN_ANNULLED_BRANCH_P (this_insn))
                  if (INSN_ANNULLED_BRANCH_P (this_insn))
                    return 0;
                    return 0;
                  code = JUMP_INSN;
                  code = JUMP_INSN;
                }
                }
 
 
              if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
              if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
                return 0;
                return 0;
              if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
              if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
                {
                {
                  if (GET_CODE (SET_DEST (set)) != MEM)
                  if (GET_CODE (SET_DEST (set)) != MEM)
                    retval = 1;
                    retval = 1;
                  else
                  else
                    return 0;
                    return 0;
                }
                }
              if (set == 0
              if (set == 0
                  && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
                  && reg_overlap_mentioned_p (reg, PATTERN (this_insn)))
                return 0;
                return 0;
            }
            }
          if (retval == 1)
          if (retval == 1)
            return 1;
            return 1;
          else if (code == JUMP_INSN)
          else if (code == JUMP_INSN)
            return 0;
            return 0;
        }
        }
 
 
      if (code == CALL_INSN)
      if (code == CALL_INSN)
        {
        {
          rtx tem;
          rtx tem;
          for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
          for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
            if (GET_CODE (XEXP (tem, 0)) == USE
            if (GET_CODE (XEXP (tem, 0)) == USE
                && REG_P (XEXP (XEXP (tem, 0), 0))
                && REG_P (XEXP (XEXP (tem, 0), 0))
                && reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
                && reg_overlap_mentioned_p (reg, XEXP (XEXP (tem, 0), 0)))
              return 0;
              return 0;
          if (call_used_regs[REGNO (reg)])
          if (call_used_regs[REGNO (reg)])
            return 1;
            return 1;
        }
        }
 
 
      set = single_set (insn);
      set = single_set (insn);
 
 
      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
      if (set && reg_overlap_mentioned_p (reg, SET_SRC (set)))
        return 0;
        return 0;
      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
      if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
        return GET_CODE (SET_DEST (set)) != MEM;
        return GET_CODE (SET_DEST (set)) != MEM;
      if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
      if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
        return 0;
        return 0;
    }
    }
  return 1;
  return 1;
}
}
 
 
/* Target hook for assembling integer objects.  The AVR version needs
/* Target hook for assembling integer objects.  The AVR version needs
   special handling for references to certain labels.  */
   special handling for references to certain labels.  */
 
 
static bool
static bool
avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
{
  if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
  if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
      && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
      && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
          || GET_CODE (x) == LABEL_REF))
          || GET_CODE (x) == LABEL_REF))
    {
    {
      fputs ("\t.word\tpm(", asm_out_file);
      fputs ("\t.word\tpm(", asm_out_file);
      output_addr_const (asm_out_file, x);
      output_addr_const (asm_out_file, x);
      fputs (")\n", asm_out_file);
      fputs (")\n", asm_out_file);
      return true;
      return true;
    }
    }
  return default_assemble_integer (x, size, aligned_p);
  return default_assemble_integer (x, size, aligned_p);
}
}
 
 
/* The routine used to output NUL terminated strings.  We use a special
/* The routine used to output NUL terminated strings.  We use a special
   version of this for most svr4 targets because doing so makes the
   version of this for most svr4 targets because doing so makes the
   generated assembly code more compact (and thus faster to assemble)
   generated assembly code more compact (and thus faster to assemble)
   as well as more readable, especially for targets like the i386
   as well as more readable, especially for targets like the i386
   (where the only alternative is to output character sequences as
   (where the only alternative is to output character sequences as
   comma separated lists of numbers).  */
   comma separated lists of numbers).  */
 
 
void
void
gas_output_limited_string(FILE *file, const char *str)
gas_output_limited_string(FILE *file, const char *str)
{
{
  const unsigned char *_limited_str = (unsigned char *) str;
  const unsigned char *_limited_str = (unsigned char *) str;
  unsigned ch;
  unsigned ch;
  fprintf (file, "%s\"", STRING_ASM_OP);
  fprintf (file, "%s\"", STRING_ASM_OP);
  for (; (ch = *_limited_str); _limited_str++)
  for (; (ch = *_limited_str); _limited_str++)
    {
    {
      int escape;
      int escape;
      switch (escape = ESCAPES[ch])
      switch (escape = ESCAPES[ch])
        {
        {
        case 0:
        case 0:
          putc (ch, file);
          putc (ch, file);
          break;
          break;
        case 1:
        case 1:
          fprintf (file, "\\%03o", ch);
          fprintf (file, "\\%03o", ch);
          break;
          break;
        default:
        default:
          putc ('\\', file);
          putc ('\\', file);
          putc (escape, file);
          putc (escape, file);
          break;
          break;
        }
        }
    }
    }
  fprintf (file, "\"\n");
  fprintf (file, "\"\n");
}
}
 
 
/* The routine used to output sequences of byte values.  We use a special
/* 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
   version of this for most svr4 targets because doing so makes the
   generated assembly code more compact (and thus faster to assemble)
   generated assembly code more compact (and thus faster to assemble)
   as well as more readable.  Note that if we find subparts of the
   as well as more readable.  Note that if we find subparts of the
   character sequence which end with NUL (and which are shorter than
   character sequence which end with NUL (and which are shorter than
   STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING.  */
   STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING.  */
 
 
void
void
gas_output_ascii(FILE *file, const char *str, size_t length)
gas_output_ascii(FILE *file, const char *str, size_t length)
{
{
  const unsigned char *_ascii_bytes = (const unsigned char *) str;
  const unsigned char *_ascii_bytes = (const unsigned char *) str;
  const unsigned char *limit = _ascii_bytes + length;
  const unsigned char *limit = _ascii_bytes + length;
  unsigned bytes_in_chunk = 0;
  unsigned bytes_in_chunk = 0;
  for (; _ascii_bytes < limit; _ascii_bytes++)
  for (; _ascii_bytes < limit; _ascii_bytes++)
    {
    {
      const unsigned char *p;
      const unsigned char *p;
      if (bytes_in_chunk >= 60)
      if (bytes_in_chunk >= 60)
        {
        {
          fprintf (file, "\"\n");
          fprintf (file, "\"\n");
          bytes_in_chunk = 0;
          bytes_in_chunk = 0;
        }
        }
      for (p = _ascii_bytes; p < limit && *p != '\0'; p++)
      for (p = _ascii_bytes; p < limit && *p != '\0'; p++)
        continue;
        continue;
      if (p < limit && (p - _ascii_bytes) <= (signed)STRING_LIMIT)
      if (p < limit && (p - _ascii_bytes) <= (signed)STRING_LIMIT)
        {
        {
          if (bytes_in_chunk > 0)
          if (bytes_in_chunk > 0)
            {
            {
              fprintf (file, "\"\n");
              fprintf (file, "\"\n");
              bytes_in_chunk = 0;
              bytes_in_chunk = 0;
            }
            }
          gas_output_limited_string (file, (char*)_ascii_bytes);
          gas_output_limited_string (file, (char*)_ascii_bytes);
          _ascii_bytes = p;
          _ascii_bytes = p;
        }
        }
      else
      else
        {
        {
          int escape;
          int escape;
          unsigned ch;
          unsigned ch;
          if (bytes_in_chunk == 0)
          if (bytes_in_chunk == 0)
            fprintf (file, "\t.ascii\t\"");
            fprintf (file, "\t.ascii\t\"");
          switch (escape = ESCAPES[ch = *_ascii_bytes])
          switch (escape = ESCAPES[ch = *_ascii_bytes])
            {
            {
            case 0:
            case 0:
              putc (ch, file);
              putc (ch, file);
              bytes_in_chunk++;
              bytes_in_chunk++;
              break;
              break;
            case 1:
            case 1:
              fprintf (file, "\\%03o", ch);
              fprintf (file, "\\%03o", ch);
              bytes_in_chunk += 4;
              bytes_in_chunk += 4;
              break;
              break;
            default:
            default:
              putc ('\\', file);
              putc ('\\', file);
              putc (escape, file);
              putc (escape, file);
              bytes_in_chunk += 2;
              bytes_in_chunk += 2;
              break;
              break;
            }
            }
        }
        }
    }
    }
  if (bytes_in_chunk > 0)
  if (bytes_in_chunk > 0)
    fprintf (file, "\"\n");
    fprintf (file, "\"\n");
}
}
 
 
/* Return value is nonzero if pseudos that have been
/* Return value is nonzero if pseudos that have been
   assigned to registers of class CLASS would likely be spilled
   assigned to registers of class CLASS would likely be spilled
   because registers of CLASS are needed for spill registers.  */
   because registers of CLASS are needed for spill registers.  */
 
 
enum reg_class
enum reg_class
class_likely_spilled_p (int c)
class_likely_spilled_p (int c)
{
{
  return (c != ALL_REGS && c != ADDW_REGS);
  return (c != ALL_REGS && c != ADDW_REGS);
}
}
 
 
/* Valid attributes:
/* Valid attributes:
   progmem - put data to program memory;
   progmem - put data to program memory;
   signal - make a function to be hardware interrupt. After function
   signal - make a function to be hardware interrupt. After function
   prologue interrupts are disabled;
   prologue interrupts are disabled;
   interrupt - make a function to be hardware interrupt. After function
   interrupt - make a function to be hardware interrupt. After function
   prologue interrupts are enabled;
   prologue interrupts are enabled;
   naked     - don't generate function prologue/epilogue and `ret' command.
   naked     - don't generate function prologue/epilogue and `ret' command.
 
 
   Only `progmem' attribute valid for type.  */
   Only `progmem' attribute valid for type.  */
 
 
const struct attribute_spec avr_attribute_table[] =
const struct attribute_spec avr_attribute_table[] =
{
{
  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
  { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute },
  { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute },
  { "signal",    0, 0, true,  false, false,  avr_handle_fndecl_attribute },
  { "signal",    0, 0, true,  false, false,  avr_handle_fndecl_attribute },
  { "interrupt", 0, 0, true,  false, false,  avr_handle_fndecl_attribute },
  { "interrupt", 0, 0, true,  false, false,  avr_handle_fndecl_attribute },
  { "naked",     0, 0, false, true,  true,   avr_handle_fntype_attribute },
  { "naked",     0, 0, false, true,  true,   avr_handle_fntype_attribute },
  { NULL,        0, 0, false, false, false, NULL }
  { NULL,        0, 0, false, false, false, NULL }
};
};
 
 
/* Handle a "progmem" attribute; arguments as in
/* Handle a "progmem" attribute; arguments as in
   struct attribute_spec.handler.  */
   struct attribute_spec.handler.  */
static tree
static tree
avr_handle_progmem_attribute (tree *node, tree name,
avr_handle_progmem_attribute (tree *node, tree name,
                              tree args ATTRIBUTE_UNUSED,
                              tree args ATTRIBUTE_UNUSED,
                              int flags ATTRIBUTE_UNUSED,
                              int flags ATTRIBUTE_UNUSED,
                              bool *no_add_attrs)
                              bool *no_add_attrs)
{
{
  if (DECL_P (*node))
  if (DECL_P (*node))
    {
    {
      if (TREE_CODE (*node) == TYPE_DECL)
      if (TREE_CODE (*node) == TYPE_DECL)
        {
        {
          /* This is really a decl attribute, not a type attribute,
          /* This is really a decl attribute, not a type attribute,
             but try to handle it for GCC 3.0 backwards compatibility.  */
             but try to handle it for GCC 3.0 backwards compatibility.  */
 
 
          tree type = TREE_TYPE (*node);
          tree type = TREE_TYPE (*node);
          tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type));
          tree attr = tree_cons (name, args, TYPE_ATTRIBUTES (type));
          tree newtype = build_type_attribute_variant (type, attr);
          tree newtype = build_type_attribute_variant (type, attr);
 
 
          TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
          TYPE_MAIN_VARIANT (newtype) = TYPE_MAIN_VARIANT (type);
          TREE_TYPE (*node) = newtype;
          TREE_TYPE (*node) = newtype;
          *no_add_attrs = true;
          *no_add_attrs = true;
        }
        }
      else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
      else if (TREE_STATIC (*node) || DECL_EXTERNAL (*node))
        {
        {
          if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
          if (DECL_INITIAL (*node) == NULL_TREE && !DECL_EXTERNAL (*node))
            {
            {
              warning (0, "only initialized variables can be placed into "
              warning (0, "only initialized variables can be placed into "
                       "program memory area");
                       "program memory area");
              *no_add_attrs = true;
              *no_add_attrs = true;
            }
            }
        }
        }
      else
      else
        {
        {
          warning (OPT_Wattributes, "%qs attribute ignored",
          warning (OPT_Wattributes, "%qs attribute ignored",
                   IDENTIFIER_POINTER (name));
                   IDENTIFIER_POINTER (name));
          *no_add_attrs = true;
          *no_add_attrs = true;
        }
        }
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
   struct attribute_spec.handler.  */
   struct attribute_spec.handler.  */
 
 
static tree
static tree
avr_handle_fndecl_attribute (tree *node, tree name,
avr_handle_fndecl_attribute (tree *node, tree name,
                             tree args ATTRIBUTE_UNUSED,
                             tree args ATTRIBUTE_UNUSED,
                             int flags ATTRIBUTE_UNUSED,
                             int flags ATTRIBUTE_UNUSED,
                             bool *no_add_attrs)
                             bool *no_add_attrs)
{
{
  if (TREE_CODE (*node) != FUNCTION_DECL)
  if (TREE_CODE (*node) != FUNCTION_DECL)
    {
    {
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
               IDENTIFIER_POINTER (name));
      *no_add_attrs = true;
      *no_add_attrs = true;
    }
    }
  else
  else
    {
    {
      const char *func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (*node));
      const char *func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (*node));
      const char *attr = IDENTIFIER_POINTER (name);
      const char *attr = IDENTIFIER_POINTER (name);
 
 
      /* If the function has the 'signal' or 'interrupt' attribute, test to
      /* If the function has the 'signal' or 'interrupt' attribute, test to
         make sure that the name of the function is "__vector_NN" so as to
         make sure that the name of the function is "__vector_NN" so as to
         catch when the user misspells the interrupt vector name.  */
         catch when the user misspells the interrupt vector name.  */
 
 
      if (strncmp (attr, "interrupt", strlen ("interrupt")) == 0)
      if (strncmp (attr, "interrupt", strlen ("interrupt")) == 0)
        {
        {
          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
            {
            {
              warning (0, "%qs appears to be a misspelled interrupt handler",
              warning (0, "%qs appears to be a misspelled interrupt handler",
                       func_name);
                       func_name);
            }
            }
        }
        }
      else if (strncmp (attr, "signal", strlen ("signal")) == 0)
      else if (strncmp (attr, "signal", strlen ("signal")) == 0)
        {
        {
          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
            {
            {
              warning (0, "%qs appears to be a misspelled signal handler",
              warning (0, "%qs appears to be a misspelled signal handler",
                       func_name);
                       func_name);
            }
            }
        }
        }
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
static tree
static tree
avr_handle_fntype_attribute (tree *node, tree name,
avr_handle_fntype_attribute (tree *node, tree name,
                             tree args ATTRIBUTE_UNUSED,
                             tree args ATTRIBUTE_UNUSED,
                             int flags ATTRIBUTE_UNUSED,
                             int flags ATTRIBUTE_UNUSED,
                             bool *no_add_attrs)
                             bool *no_add_attrs)
{
{
  if (TREE_CODE (*node) != FUNCTION_TYPE)
  if (TREE_CODE (*node) != FUNCTION_TYPE)
    {
    {
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
               IDENTIFIER_POINTER (name));
      *no_add_attrs = true;
      *no_add_attrs = true;
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Look for attribute `progmem' in DECL
/* Look for attribute `progmem' in DECL
   if found return 1, otherwise 0.  */
   if found return 1, otherwise 0.  */
 
 
int
int
avr_progmem_p (tree decl, tree attributes)
avr_progmem_p (tree decl, tree attributes)
{
{
  tree a;
  tree a;
 
 
  if (TREE_CODE (decl) != VAR_DECL)
  if (TREE_CODE (decl) != VAR_DECL)
    return 0;
    return 0;
 
 
  if (NULL_TREE
  if (NULL_TREE
      != lookup_attribute ("progmem", attributes))
      != lookup_attribute ("progmem", attributes))
    return 1;
    return 1;
 
 
  a=decl;
  a=decl;
  do
  do
    a = TREE_TYPE(a);
    a = TREE_TYPE(a);
  while (TREE_CODE (a) == ARRAY_TYPE);
  while (TREE_CODE (a) == ARRAY_TYPE);
 
 
  if (a == error_mark_node)
  if (a == error_mark_node)
    return 0;
    return 0;
 
 
  if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
  if (NULL_TREE != lookup_attribute ("progmem", TYPE_ATTRIBUTES (a)))
    return 1;
    return 1;
 
 
  return 0;
  return 0;
}
}
 
 
/* Add the section attribute if the variable is in progmem.  */
/* Add the section attribute if the variable is in progmem.  */
 
 
static void
static void
avr_insert_attributes (tree node, tree *attributes)
avr_insert_attributes (tree node, tree *attributes)
{
{
  if (TREE_CODE (node) == VAR_DECL
  if (TREE_CODE (node) == VAR_DECL
      && (TREE_STATIC (node) || DECL_EXTERNAL (node))
      && (TREE_STATIC (node) || DECL_EXTERNAL (node))
      && avr_progmem_p (node, *attributes))
      && avr_progmem_p (node, *attributes))
    {
    {
      static const char dsec[] = ".progmem.data";
      static const char dsec[] = ".progmem.data";
      *attributes = tree_cons (get_identifier ("section"),
      *attributes = tree_cons (get_identifier ("section"),
                build_tree_list (NULL, build_string (strlen (dsec), dsec)),
                build_tree_list (NULL, build_string (strlen (dsec), dsec)),
                *attributes);
                *attributes);
 
 
      /* ??? This seems sketchy.  Why can't the user declare the
      /* ??? This seems sketchy.  Why can't the user declare the
         thing const in the first place?  */
         thing const in the first place?  */
      TREE_READONLY (node) = 1;
      TREE_READONLY (node) = 1;
    }
    }
}
}
 
 
/* A get_unnamed_section callback for switching to progmem_section.  */
/* A get_unnamed_section callback for switching to progmem_section.  */
 
 
static void
static void
avr_output_progmem_section_asm_op (const void *arg ATTRIBUTE_UNUSED)
avr_output_progmem_section_asm_op (const void *arg ATTRIBUTE_UNUSED)
{
{
  fprintf (asm_out_file,
  fprintf (asm_out_file,
           "\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",
           "\t.section .progmem.gcc_sw_table, \"%s\", @progbits\n",
           AVR_MEGA ? "a" : "ax");
           AVR_MEGA ? "a" : "ax");
  /* Should already be aligned, this is just to be safe if it isn't.  */
  /* Should already be aligned, this is just to be safe if it isn't.  */
  fprintf (asm_out_file, "\t.p2align 1\n");
  fprintf (asm_out_file, "\t.p2align 1\n");
}
}
 
 
/* Implement TARGET_ASM_INIT_SECTIONS.  */
/* Implement TARGET_ASM_INIT_SECTIONS.  */
 
 
static void
static void
avr_asm_init_sections (void)
avr_asm_init_sections (void)
{
{
  progmem_section = get_unnamed_section (AVR_MEGA ? 0 : SECTION_CODE,
  progmem_section = get_unnamed_section (AVR_MEGA ? 0 : SECTION_CODE,
                                         avr_output_progmem_section_asm_op,
                                         avr_output_progmem_section_asm_op,
                                         NULL);
                                         NULL);
  readonly_data_section = data_section;
  readonly_data_section = data_section;
}
}
 
 
static unsigned int
static unsigned int
avr_section_type_flags (tree decl, const char *name, int reloc)
avr_section_type_flags (tree decl, const char *name, int reloc)
{
{
  unsigned int flags = default_section_type_flags (decl, name, reloc);
  unsigned int flags = default_section_type_flags (decl, name, reloc);
 
 
  if (strncmp (name, ".noinit", 7) == 0)
  if (strncmp (name, ".noinit", 7) == 0)
    {
    {
      if (decl && TREE_CODE (decl) == VAR_DECL
      if (decl && TREE_CODE (decl) == VAR_DECL
          && DECL_INITIAL (decl) == NULL_TREE)
          && DECL_INITIAL (decl) == NULL_TREE)
        flags |= SECTION_BSS;  /* @nobits */
        flags |= SECTION_BSS;  /* @nobits */
      else
      else
        warning (0, "only uninitialized variables can be placed in the "
        warning (0, "only uninitialized variables can be placed in the "
                 ".noinit section");
                 ".noinit section");
    }
    }
 
 
  return flags;
  return flags;
}
}
 
 
/* Outputs some appropriate text to go at the start of an assembler
/* Outputs some appropriate text to go at the start of an assembler
   file.  */
   file.  */
 
 
static void
static void
avr_file_start (void)
avr_file_start (void)
{
{
  if (avr_asm_only_p)
  if (avr_asm_only_p)
    error ("MCU %qs supported for assembler only", avr_mcu_name);
    error ("MCU %qs supported for assembler only", avr_mcu_name);
 
 
  default_file_start ();
  default_file_start ();
 
 
/*  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
/*  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
  fputs ("__SREG__ = 0x3f\n"
  fputs ("__SREG__ = 0x3f\n"
         "__SP_H__ = 0x3e\n"
         "__SP_H__ = 0x3e\n"
         "__SP_L__ = 0x3d\n", asm_out_file);
         "__SP_L__ = 0x3d\n", asm_out_file);
 
 
  fputs ("__tmp_reg__ = 0\n"
  fputs ("__tmp_reg__ = 0\n"
         "__zero_reg__ = 1\n", asm_out_file);
         "__zero_reg__ = 1\n", asm_out_file);
 
 
  /* FIXME: output these only if there is anything in the .data / .bss
  /* FIXME: output these only if there is anything in the .data / .bss
     sections - some code size could be saved by not linking in the
     sections - some code size could be saved by not linking in the
     initialization code from libgcc if one or both sections are empty.  */
     initialization code from libgcc if one or both sections are empty.  */
  fputs ("\t.global __do_copy_data\n", asm_out_file);
  fputs ("\t.global __do_copy_data\n", asm_out_file);
  fputs ("\t.global __do_clear_bss\n", asm_out_file);
  fputs ("\t.global __do_clear_bss\n", asm_out_file);
 
 
  commands_in_file = 0;
  commands_in_file = 0;
  commands_in_prologues = 0;
  commands_in_prologues = 0;
  commands_in_epilogues = 0;
  commands_in_epilogues = 0;
}
}
 
 
/* Outputs to the stdio stream FILE some
/* Outputs to the stdio stream FILE some
   appropriate text to go at the end of an assembler file.  */
   appropriate text to go at the end of an assembler file.  */
 
 
static void
static void
avr_file_end (void)
avr_file_end (void)
{
{
  fputs ("/* File ", asm_out_file);
  fputs ("/* File ", asm_out_file);
  output_quoted_string (asm_out_file, main_input_filename);
  output_quoted_string (asm_out_file, main_input_filename);
  fprintf (asm_out_file,
  fprintf (asm_out_file,
           ": code %4d = 0x%04x (%4d), prologues %3d, epilogues %3d */\n",
           ": code %4d = 0x%04x (%4d), prologues %3d, epilogues %3d */\n",
           commands_in_file,
           commands_in_file,
           commands_in_file,
           commands_in_file,
           commands_in_file - commands_in_prologues - commands_in_epilogues,
           commands_in_file - commands_in_prologues - commands_in_epilogues,
           commands_in_prologues, commands_in_epilogues);
           commands_in_prologues, commands_in_epilogues);
}
}
 
 
/* Choose the order in which to allocate hard registers for
/* Choose the order in which to allocate hard registers for
   pseudo-registers local to a basic block.
   pseudo-registers local to a basic block.
 
 
   Store the desired register order in the array `reg_alloc_order'.
   Store the desired register order in the array `reg_alloc_order'.
   Element 0 should be the register to allocate first; element 1, the
   Element 0 should be the register to allocate first; element 1, the
   next register; and so on.  */
   next register; and so on.  */
 
 
void
void
order_regs_for_local_alloc (void)
order_regs_for_local_alloc (void)
{
{
  unsigned int i;
  unsigned int i;
  static const int order_0[] = {
  static const int order_0[] = {
    24,25,
    24,25,
    18,19,
    18,19,
    20,21,
    20,21,
    22,23,
    22,23,
    30,31,
    30,31,
    26,27,
    26,27,
    28,29,
    28,29,
    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
    0,1,
    0,1,
    32,33,34,35
    32,33,34,35
  };
  };
  static const int order_1[] = {
  static const int order_1[] = {
    18,19,
    18,19,
    20,21,
    20,21,
    22,23,
    22,23,
    24,25,
    24,25,
    30,31,
    30,31,
    26,27,
    26,27,
    28,29,
    28,29,
    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
    17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,
    0,1,
    0,1,
    32,33,34,35
    32,33,34,35
  };
  };
  static const int order_2[] = {
  static const int order_2[] = {
    25,24,
    25,24,
    23,22,
    23,22,
    21,20,
    21,20,
    19,18,
    19,18,
    30,31,
    30,31,
    26,27,
    26,27,
    28,29,
    28,29,
    17,16,
    17,16,
    15,14,13,12,11,10,9,8,7,6,5,4,3,2,
    15,14,13,12,11,10,9,8,7,6,5,4,3,2,
    1,0,
    1,0,
    32,33,34,35
    32,33,34,35
  };
  };
 
 
  const int *order = (TARGET_ORDER_1 ? order_1 :
  const int *order = (TARGET_ORDER_1 ? order_1 :
                      TARGET_ORDER_2 ? order_2 :
                      TARGET_ORDER_2 ? order_2 :
                      order_0);
                      order_0);
  for (i=0; i < ARRAY_SIZE (order_0); ++i)
  for (i=0; i < ARRAY_SIZE (order_0); ++i)
      reg_alloc_order[i] = order[i];
      reg_alloc_order[i] = order[i];
}
}
 
 
 
 
/* Mutually recursive subroutine of avr_rtx_cost for calculating the
/* Mutually recursive subroutine of avr_rtx_cost for calculating the
   cost of an RTX operand given its context.  X is the rtx of the
   cost of an RTX operand given its context.  X is the rtx of the
   operand, MODE is its mode, and OUTER is the rtx_code of this
   operand, MODE is its mode, and OUTER is the rtx_code of this
   operand's parent operator.  */
   operand's parent operator.  */
 
 
static int
static int
avr_operand_rtx_cost (rtx x, enum machine_mode mode, enum rtx_code outer)
avr_operand_rtx_cost (rtx x, enum machine_mode mode, enum rtx_code outer)
{
{
  enum rtx_code code = GET_CODE (x);
  enum rtx_code code = GET_CODE (x);
  int total;
  int total;
 
 
  switch (code)
  switch (code)
    {
    {
    case REG:
    case REG:
    case SUBREG:
    case SUBREG:
      return 0;
      return 0;
 
 
    case CONST_INT:
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST_DOUBLE:
      return COSTS_N_INSNS (GET_MODE_SIZE (mode));
      return COSTS_N_INSNS (GET_MODE_SIZE (mode));
 
 
    default:
    default:
      break;
      break;
    }
    }
 
 
  total = 0;
  total = 0;
  avr_rtx_costs (x, code, outer, &total);
  avr_rtx_costs (x, code, outer, &total);
  return total;
  return total;
}
}
 
 
/* The AVR backend's rtx_cost function.  X is rtx expression whose cost
/* The AVR backend's rtx_cost function.  X is rtx expression whose cost
   is to be calculated.  Return true if the complete cost has been
   is to be calculated.  Return true if the complete cost has been
   computed, and false if subexpressions should be scanned.  In either
   computed, and false if subexpressions should be scanned.  In either
   case, *TOTAL contains the cost result.  */
   case, *TOTAL contains the cost result.  */
 
 
static bool
static bool
avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
{
{
  enum machine_mode mode = GET_MODE (x);
  enum machine_mode mode = GET_MODE (x);
  HOST_WIDE_INT val;
  HOST_WIDE_INT val;
 
 
  switch (code)
  switch (code)
    {
    {
    case CONST_INT:
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST_DOUBLE:
      /* Immediate constants are as cheap as registers.  */
      /* Immediate constants are as cheap as registers.  */
      *total = 0;
      *total = 0;
      return true;
      return true;
 
 
    case MEM:
    case MEM:
    case CONST:
    case CONST:
    case LABEL_REF:
    case LABEL_REF:
    case SYMBOL_REF:
    case SYMBOL_REF:
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      return true;
      return true;
 
 
    case NEG:
    case NEG:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
        case SFmode:
        case SFmode:
          *total = COSTS_N_INSNS (1);
          *total = COSTS_N_INSNS (1);
          break;
          break;
 
 
        case HImode:
        case HImode:
          *total = COSTS_N_INSNS (3);
          *total = COSTS_N_INSNS (3);
          break;
          break;
 
 
        case SImode:
        case SImode:
          *total = COSTS_N_INSNS (7);
          *total = COSTS_N_INSNS (7);
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case ABS:
    case ABS:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
        case SFmode:
        case SFmode:
          *total = COSTS_N_INSNS (1);
          *total = COSTS_N_INSNS (1);
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case NOT:
    case NOT:
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case ZERO_EXTEND:
    case ZERO_EXTEND:
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)
                              - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
                              - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case SIGN_EXTEND:
    case SIGN_EXTEND:
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) + 2
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) + 2
                              - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
                              - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case PLUS:
    case PLUS:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
          *total = COSTS_N_INSNS (1);
          *total = COSTS_N_INSNS (1);
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
          break;
          break;
 
 
        case HImode:
        case HImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (2);
              *total = COSTS_N_INSNS (2);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
          else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
            *total = COSTS_N_INSNS (1);
            *total = COSTS_N_INSNS (1);
          else
          else
            *total = COSTS_N_INSNS (2);
            *total = COSTS_N_INSNS (2);
          break;
          break;
 
 
        case SImode:
        case SImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (4);
              *total = COSTS_N_INSNS (4);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
          else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
            *total = COSTS_N_INSNS (1);
            *total = COSTS_N_INSNS (1);
          else
          else
            *total = COSTS_N_INSNS (4);
            *total = COSTS_N_INSNS (4);
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case MINUS:
    case MINUS:
    case AND:
    case AND:
    case IOR:
    case IOR:
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
      if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
          *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      return true;
      return true;
 
 
    case XOR:
    case XOR:
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      return true;
      return true;
 
 
    case MULT:
    case MULT:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
          if (AVR_ENHANCED)
          if (AVR_ENHANCED)
            *total = COSTS_N_INSNS (optimize_size ? 3 : 4);
            *total = COSTS_N_INSNS (optimize_size ? 3 : 4);
          else if (optimize_size)
          else if (optimize_size)
            *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
            *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
          else
          else
            return false;
            return false;
          break;
          break;
 
 
        case HImode:
        case HImode:
          if (AVR_ENHANCED)
          if (AVR_ENHANCED)
            *total = COSTS_N_INSNS (optimize_size ? 7 : 10);
            *total = COSTS_N_INSNS (optimize_size ? 7 : 10);
          else if (optimize_size)
          else if (optimize_size)
            *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
            *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
          else
          else
            return false;
            return false;
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      return true;
      return true;
 
 
    case DIV:
    case DIV:
    case MOD:
    case MOD:
    case UDIV:
    case UDIV:
    case UMOD:
    case UMOD:
      if (optimize_size)
      if (optimize_size)
        *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
        *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
      else
      else
        return false;
        return false;
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
      return true;
      return true;
 
 
    case ASHIFT:
    case ASHIFT:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
              *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            {
            {
              val = INTVAL (XEXP (x, 1));
              val = INTVAL (XEXP (x, 1));
              if (val == 7)
              if (val == 7)
                *total = COSTS_N_INSNS (3);
                *total = COSTS_N_INSNS (3);
              else if (val >= 0 && val <= 7)
              else if (val >= 0 && val <= 7)
                *total = COSTS_N_INSNS (val);
                *total = COSTS_N_INSNS (val);
              else
              else
                *total = COSTS_N_INSNS (1);
                *total = COSTS_N_INSNS (1);
            }
            }
          break;
          break;
 
 
        case HImode:
        case HImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
              *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            switch (INTVAL (XEXP (x, 1)))
            switch (INTVAL (XEXP (x, 1)))
              {
              {
              case 0:
              case 0:
                *total = 0;
                *total = 0;
                break;
                break;
              case 1:
              case 1:
              case 8:
              case 8:
                *total = COSTS_N_INSNS (2);
                *total = COSTS_N_INSNS (2);
                break;
                break;
              case 9:
              case 9:
                *total = COSTS_N_INSNS (3);
                *total = COSTS_N_INSNS (3);
                break;
                break;
              case 2:
              case 2:
              case 3:
              case 3:
              case 10:
              case 10:
              case 15:
              case 15:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 7:
              case 7:
              case 11:
              case 11:
              case 12:
              case 12:
                *total = COSTS_N_INSNS (5);
                *total = COSTS_N_INSNS (5);
                break;
                break;
              case 4:
              case 4:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
                break;
                break;
              case 6:
              case 6:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
                break;
                break;
              case 5:
              case 5:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 10);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 10);
                break;
                break;
              default:
              default:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              }
              }
          break;
          break;
 
 
        case SImode:
        case SImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
              *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            switch (INTVAL (XEXP (x, 1)))
            switch (INTVAL (XEXP (x, 1)))
              {
              {
              case 0:
              case 0:
                *total = 0;
                *total = 0;
                break;
                break;
              case 24:
              case 24:
                *total = COSTS_N_INSNS (3);
                *total = COSTS_N_INSNS (3);
                break;
                break;
              case 1:
              case 1:
              case 8:
              case 8:
              case 16:
              case 16:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 31:
              case 31:
                *total = COSTS_N_INSNS (6);
                *total = COSTS_N_INSNS (6);
                break;
                break;
              case 2:
              case 2:
                *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
                *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
                break;
                break;
              default:
              default:
                *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
                *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              }
              }
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case ASHIFTRT:
    case ASHIFTRT:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
              *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            {
            {
              val = INTVAL (XEXP (x, 1));
              val = INTVAL (XEXP (x, 1));
              if (val == 6)
              if (val == 6)
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
              else if (val == 7)
              else if (val == 7)
                *total = COSTS_N_INSNS (2);
                *total = COSTS_N_INSNS (2);
              else if (val >= 0 && val <= 7)
              else if (val >= 0 && val <= 7)
                *total = COSTS_N_INSNS (val);
                *total = COSTS_N_INSNS (val);
              else
              else
                *total = COSTS_N_INSNS (1);
                *total = COSTS_N_INSNS (1);
            }
            }
          break;
          break;
 
 
        case HImode:
        case HImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
              *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            switch (INTVAL (XEXP (x, 1)))
            switch (INTVAL (XEXP (x, 1)))
              {
              {
              case 0:
              case 0:
                *total = 0;
                *total = 0;
                break;
                break;
              case 1:
              case 1:
                *total = COSTS_N_INSNS (2);
                *total = COSTS_N_INSNS (2);
                break;
                break;
              case 15:
              case 15:
                *total = COSTS_N_INSNS (3);
                *total = COSTS_N_INSNS (3);
                break;
                break;
              case 2:
              case 2:
              case 7:
              case 7:
              case 8:
              case 8:
              case 9:
              case 9:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 10:
              case 10:
              case 14:
              case 14:
                *total = COSTS_N_INSNS (5);
                *total = COSTS_N_INSNS (5);
                break;
                break;
              case 11:
              case 11:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
                break;
                break;
              case 12:
              case 12:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
                break;
                break;
              case 6:
              case 6:
              case 13:
              case 13:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
                break;
                break;
              default:
              default:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              }
              }
          break;
          break;
 
 
        case SImode:
        case SImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
              *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            switch (INTVAL (XEXP (x, 1)))
            switch (INTVAL (XEXP (x, 1)))
              {
              {
              case 0:
              case 0:
                *total = 0;
                *total = 0;
                break;
                break;
              case 1:
              case 1:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 8:
              case 8:
              case 16:
              case 16:
              case 24:
              case 24:
                *total = COSTS_N_INSNS (6);
                *total = COSTS_N_INSNS (6);
                break;
                break;
              case 2:
              case 2:
                *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
                *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
                break;
                break;
              case 31:
              case 31:
                *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 5);
                *total = COSTS_N_INSNS (AVR_HAVE_MOVW ? 4 : 5);
                break;
                break;
              default:
              default:
                *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
                *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              }
              }
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case LSHIFTRT:
    case LSHIFTRT:
      switch (mode)
      switch (mode)
        {
        {
        case QImode:
        case QImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
              *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            {
            {
              val = INTVAL (XEXP (x, 1));
              val = INTVAL (XEXP (x, 1));
              if (val == 7)
              if (val == 7)
                *total = COSTS_N_INSNS (3);
                *total = COSTS_N_INSNS (3);
              else if (val >= 0 && val <= 7)
              else if (val >= 0 && val <= 7)
                *total = COSTS_N_INSNS (val);
                *total = COSTS_N_INSNS (val);
              else
              else
                *total = COSTS_N_INSNS (1);
                *total = COSTS_N_INSNS (1);
            }
            }
          break;
          break;
 
 
        case HImode:
        case HImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
              *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            switch (INTVAL (XEXP (x, 1)))
            switch (INTVAL (XEXP (x, 1)))
              {
              {
              case 0:
              case 0:
                *total = 0;
                *total = 0;
                break;
                break;
              case 1:
              case 1:
              case 8:
              case 8:
                *total = COSTS_N_INSNS (2);
                *total = COSTS_N_INSNS (2);
                break;
                break;
              case 9:
              case 9:
                *total = COSTS_N_INSNS (3);
                *total = COSTS_N_INSNS (3);
                break;
                break;
              case 2:
              case 2:
              case 10:
              case 10:
              case 15:
              case 15:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 7:
              case 7:
              case 11:
              case 11:
                *total = COSTS_N_INSNS (5);
                *total = COSTS_N_INSNS (5);
                break;
                break;
              case 3:
              case 3:
              case 12:
              case 12:
              case 13:
              case 13:
              case 14:
              case 14:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
                break;
                break;
              case 4:
              case 4:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
                break;
                break;
              case 5:
              case 5:
              case 6:
              case 6:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 9);
                break;
                break;
              default:
              default:
                *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
                *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              }
              }
          break;
          break;
 
 
        case SImode:
        case SImode:
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            {
            {
              *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
              *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            }
            }
          else
          else
            switch (INTVAL (XEXP (x, 1)))
            switch (INTVAL (XEXP (x, 1)))
              {
              {
              case 0:
              case 0:
                *total = 0;
                *total = 0;
                break;
                break;
              case 1:
              case 1:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 2:
              case 2:
                *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
                *total = COSTS_N_INSNS (optimize_size ? 7 : 8);
                break;
                break;
              case 8:
              case 8:
              case 16:
              case 16:
              case 24:
              case 24:
                *total = COSTS_N_INSNS (4);
                *total = COSTS_N_INSNS (4);
                break;
                break;
              case 31:
              case 31:
                *total = COSTS_N_INSNS (6);
                *total = COSTS_N_INSNS (6);
                break;
                break;
              default:
              default:
                *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
                *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
                *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
              }
              }
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    case COMPARE:
    case COMPARE:
      switch (GET_MODE (XEXP (x, 0)))
      switch (GET_MODE (XEXP (x, 0)))
        {
        {
        case QImode:
        case QImode:
          *total = COSTS_N_INSNS (1);
          *total = COSTS_N_INSNS (1);
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
          break;
          break;
 
 
        case HImode:
        case HImode:
          *total = COSTS_N_INSNS (2);
          *total = COSTS_N_INSNS (2);
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
          else if (INTVAL (XEXP (x, 1)) != 0)
          else if (INTVAL (XEXP (x, 1)) != 0)
            *total += COSTS_N_INSNS (1);
            *total += COSTS_N_INSNS (1);
          break;
          break;
 
 
        case SImode:
        case SImode:
          *total = COSTS_N_INSNS (4);
          *total = COSTS_N_INSNS (4);
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
            *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
          else if (INTVAL (XEXP (x, 1)) != 0)
          else if (INTVAL (XEXP (x, 1)) != 0)
            *total += COSTS_N_INSNS (3);
            *total += COSTS_N_INSNS (3);
          break;
          break;
 
 
        default:
        default:
          return false;
          return false;
        }
        }
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
      return true;
      return true;
 
 
    default:
    default:
      break;
      break;
    }
    }
  return false;
  return false;
}
}
 
 
/* Calculate the cost of a memory address.  */
/* Calculate the cost of a memory address.  */
 
 
static int
static int
avr_address_cost (rtx x)
avr_address_cost (rtx x)
{
{
  if (GET_CODE (x) == PLUS
  if (GET_CODE (x) == PLUS
      && GET_CODE (XEXP (x,1)) == CONST_INT
      && GET_CODE (XEXP (x,1)) == CONST_INT
      && (REG_P (XEXP (x,0)) || GET_CODE (XEXP (x,0)) == SUBREG)
      && (REG_P (XEXP (x,0)) || GET_CODE (XEXP (x,0)) == SUBREG)
      && INTVAL (XEXP (x,1)) >= 61)
      && INTVAL (XEXP (x,1)) >= 61)
    return 18;
    return 18;
  if (CONSTANT_ADDRESS_P (x))
  if (CONSTANT_ADDRESS_P (x))
    {
    {
      if (avr_io_address_p (x, 1))
      if (avr_io_address_p (x, 1))
        return 2;
        return 2;
      return 4;
      return 4;
    }
    }
  return 4;
  return 4;
}
}
 
 
/* Test for extra memory constraint 'Q'.
/* Test for extra memory constraint 'Q'.
   It's a memory address based on Y or Z pointer with valid displacement.  */
   It's a memory address based on Y or Z pointer with valid displacement.  */
 
 
int
int
extra_constraint_Q (rtx x)
extra_constraint_Q (rtx x)
{
{
  if (GET_CODE (XEXP (x,0)) == PLUS
  if (GET_CODE (XEXP (x,0)) == PLUS
      && REG_P (XEXP (XEXP (x,0), 0))
      && REG_P (XEXP (XEXP (x,0), 0))
      && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
      && GET_CODE (XEXP (XEXP (x,0), 1)) == CONST_INT
      && (INTVAL (XEXP (XEXP (x,0), 1))
      && (INTVAL (XEXP (XEXP (x,0), 1))
          <= MAX_LD_OFFSET (GET_MODE (x))))
          <= MAX_LD_OFFSET (GET_MODE (x))))
    {
    {
      rtx xx = XEXP (XEXP (x,0), 0);
      rtx xx = XEXP (XEXP (x,0), 0);
      int regno = REGNO (xx);
      int regno = REGNO (xx);
      if (TARGET_ALL_DEBUG)
      if (TARGET_ALL_DEBUG)
        {
        {
          fprintf (stderr, ("extra_constraint:\n"
          fprintf (stderr, ("extra_constraint:\n"
                            "reload_completed: %d\n"
                            "reload_completed: %d\n"
                            "reload_in_progress: %d\n"),
                            "reload_in_progress: %d\n"),
                   reload_completed, reload_in_progress);
                   reload_completed, reload_in_progress);
          debug_rtx (x);
          debug_rtx (x);
        }
        }
      if (regno >= FIRST_PSEUDO_REGISTER)
      if (regno >= FIRST_PSEUDO_REGISTER)
        return 1;               /* allocate pseudos */
        return 1;               /* allocate pseudos */
      else if (regno == REG_Z || regno == REG_Y)
      else if (regno == REG_Z || regno == REG_Y)
        return 1;               /* strictly check */
        return 1;               /* strictly check */
      else if (xx == frame_pointer_rtx
      else if (xx == frame_pointer_rtx
               || xx == arg_pointer_rtx)
               || xx == arg_pointer_rtx)
        return 1;               /* XXX frame & arg pointer checks */
        return 1;               /* XXX frame & arg pointer checks */
    }
    }
  return 0;
  return 0;
}
}
 
 
/* Convert condition code CONDITION to the valid AVR condition code.  */
/* Convert condition code CONDITION to the valid AVR condition code.  */
 
 
RTX_CODE
RTX_CODE
avr_normalize_condition (RTX_CODE condition)
avr_normalize_condition (RTX_CODE condition)
{
{
  switch (condition)
  switch (condition)
    {
    {
    case GT:
    case GT:
      return GE;
      return GE;
    case GTU:
    case GTU:
      return GEU;
      return GEU;
    case LE:
    case LE:
      return LT;
      return LT;
    case LEU:
    case LEU:
      return LTU;
      return LTU;
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
}
}
 
 
/* This function optimizes conditional jumps.  */
/* This function optimizes conditional jumps.  */
 
 
static void
static void
avr_reorg (void)
avr_reorg (void)
{
{
  rtx insn, pattern;
  rtx insn, pattern;
 
 
  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
    {
    {
      if (! (GET_CODE (insn) == INSN
      if (! (GET_CODE (insn) == INSN
             || GET_CODE (insn) == CALL_INSN
             || GET_CODE (insn) == CALL_INSN
             || GET_CODE (insn) == JUMP_INSN)
             || GET_CODE (insn) == JUMP_INSN)
          || !single_set (insn))
          || !single_set (insn))
        continue;
        continue;
 
 
      pattern = PATTERN (insn);
      pattern = PATTERN (insn);
 
 
      if (GET_CODE (pattern) == PARALLEL)
      if (GET_CODE (pattern) == PARALLEL)
        pattern = XVECEXP (pattern, 0, 0);
        pattern = XVECEXP (pattern, 0, 0);
      if (GET_CODE (pattern) == SET
      if (GET_CODE (pattern) == SET
          && SET_DEST (pattern) == cc0_rtx
          && SET_DEST (pattern) == cc0_rtx
          && compare_diff_p (insn))
          && compare_diff_p (insn))
        {
        {
          if (GET_CODE (SET_SRC (pattern)) == COMPARE)
          if (GET_CODE (SET_SRC (pattern)) == COMPARE)
            {
            {
              /* Now we work under compare insn.  */
              /* Now we work under compare insn.  */
 
 
              pattern = SET_SRC (pattern);
              pattern = SET_SRC (pattern);
              if (true_regnum (XEXP (pattern,0)) >= 0
              if (true_regnum (XEXP (pattern,0)) >= 0
                  && true_regnum (XEXP (pattern,1)) >= 0 )
                  && true_regnum (XEXP (pattern,1)) >= 0 )
                {
                {
                  rtx x = XEXP (pattern,0);
                  rtx x = XEXP (pattern,0);
                  rtx next = next_real_insn (insn);
                  rtx next = next_real_insn (insn);
                  rtx pat = PATTERN (next);
                  rtx pat = PATTERN (next);
                  rtx src = SET_SRC (pat);
                  rtx src = SET_SRC (pat);
                  rtx t = XEXP (src,0);
                  rtx t = XEXP (src,0);
                  PUT_CODE (t, swap_condition (GET_CODE (t)));
                  PUT_CODE (t, swap_condition (GET_CODE (t)));
                  XEXP (pattern,0) = XEXP (pattern,1);
                  XEXP (pattern,0) = XEXP (pattern,1);
                  XEXP (pattern,1) = x;
                  XEXP (pattern,1) = x;
                  INSN_CODE (next) = -1;
                  INSN_CODE (next) = -1;
                }
                }
              else if (true_regnum (XEXP (pattern,0)) >= 0
              else if (true_regnum (XEXP (pattern,0)) >= 0
                       && GET_CODE (XEXP (pattern,1)) == CONST_INT)
                       && GET_CODE (XEXP (pattern,1)) == CONST_INT)
                {
                {
                  rtx x = XEXP (pattern,1);
                  rtx x = XEXP (pattern,1);
                  rtx next = next_real_insn (insn);
                  rtx next = next_real_insn (insn);
                  rtx pat = PATTERN (next);
                  rtx pat = PATTERN (next);
                  rtx src = SET_SRC (pat);
                  rtx src = SET_SRC (pat);
                  rtx t = XEXP (src,0);
                  rtx t = XEXP (src,0);
                  enum machine_mode mode = GET_MODE (XEXP (pattern, 0));
                  enum machine_mode mode = GET_MODE (XEXP (pattern, 0));
 
 
                  if (avr_simplify_comparison_p (mode, GET_CODE (t), x))
                  if (avr_simplify_comparison_p (mode, GET_CODE (t), x))
                    {
                    {
                      XEXP (pattern, 1) = gen_int_mode (INTVAL (x) + 1, mode);
                      XEXP (pattern, 1) = gen_int_mode (INTVAL (x) + 1, mode);
                      PUT_CODE (t, avr_normalize_condition (GET_CODE (t)));
                      PUT_CODE (t, avr_normalize_condition (GET_CODE (t)));
                      INSN_CODE (next) = -1;
                      INSN_CODE (next) = -1;
                      INSN_CODE (insn) = -1;
                      INSN_CODE (insn) = -1;
                    }
                    }
                }
                }
            }
            }
          else if (true_regnum (SET_SRC (pattern)) >= 0)
          else if (true_regnum (SET_SRC (pattern)) >= 0)
            {
            {
              /* This is a tst insn */
              /* This is a tst insn */
              rtx next = next_real_insn (insn);
              rtx next = next_real_insn (insn);
              rtx pat = PATTERN (next);
              rtx pat = PATTERN (next);
              rtx src = SET_SRC (pat);
              rtx src = SET_SRC (pat);
              rtx t = XEXP (src,0);
              rtx t = XEXP (src,0);
 
 
              PUT_CODE (t, swap_condition (GET_CODE (t)));
              PUT_CODE (t, swap_condition (GET_CODE (t)));
              SET_SRC (pattern) = gen_rtx_NEG (GET_MODE (SET_SRC (pattern)),
              SET_SRC (pattern) = gen_rtx_NEG (GET_MODE (SET_SRC (pattern)),
                                               SET_SRC (pattern));
                                               SET_SRC (pattern));
              INSN_CODE (next) = -1;
              INSN_CODE (next) = -1;
              INSN_CODE (insn) = -1;
              INSN_CODE (insn) = -1;
            }
            }
        }
        }
    }
    }
}
}
 
 
/* Returns register number for function return value.*/
/* Returns register number for function return value.*/
 
 
int
int
avr_ret_register (void)
avr_ret_register (void)
{
{
  return 24;
  return 24;
}
}
 
 
/* Ceate an RTX representing the place where a
/* Ceate an RTX representing the place where a
   library function returns a value of mode MODE.  */
   library function returns a value of mode MODE.  */
 
 
rtx
rtx
avr_libcall_value (enum machine_mode mode)
avr_libcall_value (enum machine_mode mode)
{
{
  int offs = GET_MODE_SIZE (mode);
  int offs = GET_MODE_SIZE (mode);
  if (offs < 2)
  if (offs < 2)
    offs = 2;
    offs = 2;
  return gen_rtx_REG (mode, RET_REGISTER + 2 - offs);
  return gen_rtx_REG (mode, RET_REGISTER + 2 - offs);
}
}
 
 
/* Create an RTX representing the place where a
/* Create an RTX representing the place where a
   function returns a value of data type VALTYPE.  */
   function returns a value of data type VALTYPE.  */
 
 
rtx
rtx
avr_function_value (tree type, tree func ATTRIBUTE_UNUSED)
avr_function_value (tree type, tree func ATTRIBUTE_UNUSED)
{
{
  unsigned int offs;
  unsigned int offs;
 
 
  if (TYPE_MODE (type) != BLKmode)
  if (TYPE_MODE (type) != BLKmode)
    return avr_libcall_value (TYPE_MODE (type));
    return avr_libcall_value (TYPE_MODE (type));
 
 
  offs = int_size_in_bytes (type);
  offs = int_size_in_bytes (type);
  if (offs < 2)
  if (offs < 2)
    offs = 2;
    offs = 2;
  if (offs > 2 && offs < GET_MODE_SIZE (SImode))
  if (offs > 2 && offs < GET_MODE_SIZE (SImode))
    offs = GET_MODE_SIZE (SImode);
    offs = GET_MODE_SIZE (SImode);
  else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
  else if (offs > GET_MODE_SIZE (SImode) && offs < GET_MODE_SIZE (DImode))
    offs = GET_MODE_SIZE (DImode);
    offs = GET_MODE_SIZE (DImode);
 
 
  return gen_rtx_REG (BLKmode, RET_REGISTER + 2 - offs);
  return gen_rtx_REG (BLKmode, RET_REGISTER + 2 - offs);
}
}
 
 
/* Returns nonzero if the number MASK has only one bit set.  */
/* Returns nonzero if the number MASK has only one bit set.  */
 
 
int
int
mask_one_bit_p (HOST_WIDE_INT mask)
mask_one_bit_p (HOST_WIDE_INT mask)
{
{
  int i;
  int i;
  unsigned HOST_WIDE_INT n=mask;
  unsigned HOST_WIDE_INT n=mask;
  for (i = 0; i < 32; ++i)
  for (i = 0; i < 32; ++i)
    {
    {
      if (n & 0x80000000L)
      if (n & 0x80000000L)
        {
        {
          if (n & 0x7fffffffL)
          if (n & 0x7fffffffL)
            return 0;
            return 0;
          else
          else
            return 32-i;
            return 32-i;
        }
        }
      n<<=1;
      n<<=1;
    }
    }
  return 0;
  return 0;
}
}
 
 
 
 
/* Places additional restrictions on the register class to
/* Places additional restrictions on the register class to
   use when it is necessary to copy value X into a register
   use when it is necessary to copy value X into a register
   in class CLASS.  */
   in class CLASS.  */
 
 
enum reg_class
enum reg_class
preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
{
{
  return class;
  return class;
}
}
 
 
int
int
test_hard_reg_class (enum reg_class class, rtx x)
test_hard_reg_class (enum reg_class class, rtx x)
{
{
  int regno = true_regnum (x);
  int regno = true_regnum (x);
  if (regno < 0)
  if (regno < 0)
    return 0;
    return 0;
 
 
  if (TEST_HARD_REG_CLASS (class, regno))
  if (TEST_HARD_REG_CLASS (class, regno))
    return 1;
    return 1;
 
 
  return 0;
  return 0;
}
}
 
 
 
 
int
int
jump_over_one_insn_p (rtx insn, rtx dest)
jump_over_one_insn_p (rtx insn, rtx dest)
{
{
  int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
  int uid = INSN_UID (GET_CODE (dest) == LABEL_REF
                      ? XEXP (dest, 0)
                      ? XEXP (dest, 0)
                      : dest);
                      : dest);
  int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
  int jump_addr = INSN_ADDRESSES (INSN_UID (insn));
  int dest_addr = INSN_ADDRESSES (uid);
  int dest_addr = INSN_ADDRESSES (uid);
  return dest_addr - jump_addr == get_attr_length (insn) + 1;
  return dest_addr - jump_addr == get_attr_length (insn) + 1;
}
}
 
 
/* Returns 1 if a value of mode MODE can be stored starting with hard
/* Returns 1 if a value of mode MODE can be stored starting with hard
   register number REGNO.  On the enhanced core, anything larger than
   register number REGNO.  On the enhanced core, anything larger than
   1 byte must start in even numbered register for "movw" to work
   1 byte must start in even numbered register for "movw" to work
   (this way we don't have to check for odd registers everywhere).  */
   (this way we don't have to check for odd registers everywhere).  */
 
 
int
int
avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
{
{
  /* The only thing that can go into registers r28:r29 is a Pmode.  */
  /* The only thing that can go into registers r28:r29 is a Pmode.  */
  if (regno == REG_Y && mode == Pmode)
  if (regno == REG_Y && mode == Pmode)
    return 1;
    return 1;
 
 
  /* Otherwise disallow all regno/mode combinations that span r28:r29.  */
  /* Otherwise disallow all regno/mode combinations that span r28:r29.  */
  if (regno <= (REG_Y + 1) && (regno + GET_MODE_SIZE (mode)) >= (REG_Y + 1))
  if (regno <= (REG_Y + 1) && (regno + GET_MODE_SIZE (mode)) >= (REG_Y + 1))
    return 0;
    return 0;
 
 
  if (mode == QImode)
  if (mode == QImode)
    return 1;
    return 1;
 
 
  /* Modes larger than QImode occupy consecutive registers.  */
  /* Modes larger than QImode occupy consecutive registers.  */
  if (regno + GET_MODE_SIZE (mode) > FIRST_PSEUDO_REGISTER)
  if (regno + GET_MODE_SIZE (mode) > FIRST_PSEUDO_REGISTER)
    return 0;
    return 0;
 
 
  /* All modes larger than QImode should start in an even register.  */
  /* All modes larger than QImode should start in an even register.  */
  return !(regno & 1);
  return !(regno & 1);
}
}
 
 
/* Returns 1 if X is a valid address for an I/O register of size SIZE
/* Returns 1 if X is a valid address for an I/O register of size SIZE
   (1 or 2).  Used for lds/sts -> in/out optimization.  Add 0x20 to SIZE
   (1 or 2).  Used for lds/sts -> in/out optimization.  Add 0x20 to SIZE
   to check for the lower half of I/O space (for cbi/sbi/sbic/sbis).  */
   to check for the lower half of I/O space (for cbi/sbi/sbic/sbis).  */
 
 
int
int
avr_io_address_p (rtx x, int size)
avr_io_address_p (rtx x, int size)
{
{
  return (optimize > 0 && GET_CODE (x) == CONST_INT
  return (optimize > 0 && GET_CODE (x) == CONST_INT
          && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
          && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
}
}
 
 
/* Returns nonzero (bit number + 1) if X, or -X, is a constant power of 2.  */
/* Returns nonzero (bit number + 1) if X, or -X, is a constant power of 2.  */
 
 
int
int
const_int_pow2_p (rtx x)
const_int_pow2_p (rtx x)
{
{
  if (GET_CODE (x) == CONST_INT)
  if (GET_CODE (x) == CONST_INT)
    {
    {
      HOST_WIDE_INT d = INTVAL (x);
      HOST_WIDE_INT d = INTVAL (x);
      HOST_WIDE_INT abs_d = (d >= 0) ? d : -d;
      HOST_WIDE_INT abs_d = (d >= 0) ? d : -d;
      return exact_log2 (abs_d) + 1;
      return exact_log2 (abs_d) + 1;
    }
    }
  return 0;
  return 0;
}
}
 
 
const char *
const char *
output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
{
{
  int tmp;
  int tmp;
  if (!len)
  if (!len)
    len = &tmp;
    len = &tmp;
 
 
  if (GET_CODE (operands[1]) == CONST_INT)
  if (GET_CODE (operands[1]) == CONST_INT)
    {
    {
      int val = INTVAL (operands[1]);
      int val = INTVAL (operands[1]);
      if ((val & 0xff) == 0)
      if ((val & 0xff) == 0)
        {
        {
          *len = 3;
          *len = 3;
          return (AS2 (mov,%A0,__zero_reg__) CR_TAB
          return (AS2 (mov,%A0,__zero_reg__) CR_TAB
                  AS2 (ldi,%2,hi8(%1))       CR_TAB
                  AS2 (ldi,%2,hi8(%1))       CR_TAB
                  AS2 (mov,%B0,%2));
                  AS2 (mov,%B0,%2));
        }
        }
      else if ((val & 0xff00) == 0)
      else if ((val & 0xff00) == 0)
        {
        {
          *len = 3;
          *len = 3;
          return (AS2 (ldi,%2,lo8(%1)) CR_TAB
          return (AS2 (ldi,%2,lo8(%1)) CR_TAB
                  AS2 (mov,%A0,%2)     CR_TAB
                  AS2 (mov,%A0,%2)     CR_TAB
                  AS2 (mov,%B0,__zero_reg__));
                  AS2 (mov,%B0,__zero_reg__));
        }
        }
      else if ((val & 0xff) == ((val & 0xff00) >> 8))
      else if ((val & 0xff) == ((val & 0xff00) >> 8))
        {
        {
          *len = 3;
          *len = 3;
          return (AS2 (ldi,%2,lo8(%1)) CR_TAB
          return (AS2 (ldi,%2,lo8(%1)) CR_TAB
                  AS2 (mov,%A0,%2)     CR_TAB
                  AS2 (mov,%A0,%2)     CR_TAB
                  AS2 (mov,%B0,%2));
                  AS2 (mov,%B0,%2));
        }
        }
    }
    }
  *len = 4;
  *len = 4;
  return (AS2 (ldi,%2,lo8(%1)) CR_TAB
  return (AS2 (ldi,%2,lo8(%1)) CR_TAB
          AS2 (mov,%A0,%2)     CR_TAB
          AS2 (mov,%A0,%2)     CR_TAB
          AS2 (ldi,%2,hi8(%1)) CR_TAB
          AS2 (ldi,%2,hi8(%1)) CR_TAB
          AS2 (mov,%B0,%2));
          AS2 (mov,%B0,%2));
}
}
 
 
 
 
const char *
const char *
output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
output_reload_insisf (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
{
{
  rtx src = operands[1];
  rtx src = operands[1];
  int cnst = (GET_CODE (src) == CONST_INT);
  int cnst = (GET_CODE (src) == CONST_INT);
 
 
  if (len)
  if (len)
    {
    {
      if (cnst)
      if (cnst)
        *len = 4 + ((INTVAL (src) & 0xff) != 0)
        *len = 4 + ((INTVAL (src) & 0xff) != 0)
                + ((INTVAL (src) & 0xff00) != 0)
                + ((INTVAL (src) & 0xff00) != 0)
                + ((INTVAL (src) & 0xff0000) != 0)
                + ((INTVAL (src) & 0xff0000) != 0)
                + ((INTVAL (src) & 0xff000000) != 0);
                + ((INTVAL (src) & 0xff000000) != 0);
      else
      else
        *len = 8;
        *len = 8;
 
 
      return "";
      return "";
    }
    }
 
 
  if (cnst && ((INTVAL (src) & 0xff) == 0))
  if (cnst && ((INTVAL (src) & 0xff) == 0))
    output_asm_insn (AS2 (mov, %A0, __zero_reg__), operands);
    output_asm_insn (AS2 (mov, %A0, __zero_reg__), operands);
  else
  else
    {
    {
      output_asm_insn (AS2 (ldi, %2, lo8(%1)), operands);
      output_asm_insn (AS2 (ldi, %2, lo8(%1)), operands);
      output_asm_insn (AS2 (mov, %A0, %2), operands);
      output_asm_insn (AS2 (mov, %A0, %2), operands);
    }
    }
  if (cnst && ((INTVAL (src) & 0xff00) == 0))
  if (cnst && ((INTVAL (src) & 0xff00) == 0))
    output_asm_insn (AS2 (mov, %B0, __zero_reg__), operands);
    output_asm_insn (AS2 (mov, %B0, __zero_reg__), operands);
  else
  else
    {
    {
      output_asm_insn (AS2 (ldi, %2, hi8(%1)), operands);
      output_asm_insn (AS2 (ldi, %2, hi8(%1)), operands);
      output_asm_insn (AS2 (mov, %B0, %2), operands);
      output_asm_insn (AS2 (mov, %B0, %2), operands);
    }
    }
  if (cnst && ((INTVAL (src) & 0xff0000) == 0))
  if (cnst && ((INTVAL (src) & 0xff0000) == 0))
    output_asm_insn (AS2 (mov, %C0, __zero_reg__), operands);
    output_asm_insn (AS2 (mov, %C0, __zero_reg__), operands);
  else
  else
    {
    {
      output_asm_insn (AS2 (ldi, %2, hlo8(%1)), operands);
      output_asm_insn (AS2 (ldi, %2, hlo8(%1)), operands);
      output_asm_insn (AS2 (mov, %C0, %2), operands);
      output_asm_insn (AS2 (mov, %C0, %2), operands);
    }
    }
  if (cnst && ((INTVAL (src) & 0xff000000) == 0))
  if (cnst && ((INTVAL (src) & 0xff000000) == 0))
    output_asm_insn (AS2 (mov, %D0, __zero_reg__), operands);
    output_asm_insn (AS2 (mov, %D0, __zero_reg__), operands);
  else
  else
    {
    {
      output_asm_insn (AS2 (ldi, %2, hhi8(%1)), operands);
      output_asm_insn (AS2 (ldi, %2, hhi8(%1)), operands);
      output_asm_insn (AS2 (mov, %D0, %2), operands);
      output_asm_insn (AS2 (mov, %D0, %2), operands);
    }
    }
  return "";
  return "";
}
}
 
 
void
void
avr_output_bld (rtx operands[], int bit_nr)
avr_output_bld (rtx operands[], int bit_nr)
{
{
  static char s[] = "bld %A0,0";
  static char s[] = "bld %A0,0";
 
 
  s[5] = 'A' + (bit_nr >> 3);
  s[5] = 'A' + (bit_nr >> 3);
  s[8] = '0' + (bit_nr & 7);
  s[8] = '0' + (bit_nr & 7);
  output_asm_insn (s, operands);
  output_asm_insn (s, operands);
}
}
 
 
void
void
avr_output_addr_vec_elt (FILE *stream, int value)
avr_output_addr_vec_elt (FILE *stream, int value)
{
{
  switch_to_section (progmem_section);
  switch_to_section (progmem_section);
  if (AVR_MEGA)
  if (AVR_MEGA)
    fprintf (stream, "\t.word pm(.L%d)\n", value);
    fprintf (stream, "\t.word pm(.L%d)\n", value);
  else
  else
    fprintf (stream, "\trjmp .L%d\n", value);
    fprintf (stream, "\trjmp .L%d\n", value);
 
 
  jump_tables_size++;
  jump_tables_size++;
}
}
 
 
/* Returns 1 if SCRATCH are safe to be allocated as a scratch
/* Returns 1 if SCRATCH are safe to be allocated as a scratch
   registers (for a define_peephole2) in the current function.  */
   registers (for a define_peephole2) in the current function.  */
 
 
int
int
avr_peep2_scratch_safe (rtx scratch)
avr_peep2_scratch_safe (rtx scratch)
{
{
  if ((interrupt_function_p (current_function_decl)
  if ((interrupt_function_p (current_function_decl)
       || signal_function_p (current_function_decl))
       || signal_function_p (current_function_decl))
      && leaf_function_p ())
      && leaf_function_p ())
    {
    {
      int first_reg = true_regnum (scratch);
      int first_reg = true_regnum (scratch);
      int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
      int last_reg = first_reg + GET_MODE_SIZE (GET_MODE (scratch)) - 1;
      int reg;
      int reg;
 
 
      for (reg = first_reg; reg <= last_reg; reg++)
      for (reg = first_reg; reg <= last_reg; reg++)
        {
        {
          if (!regs_ever_live[reg])
          if (!regs_ever_live[reg])
            return 0;
            return 0;
        }
        }
    }
    }
  return 1;
  return 1;
}
}
 
 
/* Output a branch that tests a single bit of a register (QI, HI or SImode)
/* Output a branch that tests a single bit of a register (QI, HI or SImode)
   or memory location in the I/O space (QImode only).
   or memory location in the I/O space (QImode only).
 
 
   Operand 0: comparison operator (must be EQ or NE, compare bit to zero).
   Operand 0: comparison operator (must be EQ or NE, compare bit to zero).
   Operand 1: register operand to test, or CONST_INT memory address.
   Operand 1: register operand to test, or CONST_INT memory address.
   Operand 2: bit number (for QImode operand) or mask (HImode, SImode).
   Operand 2: bit number (for QImode operand) or mask (HImode, SImode).
   Operand 3: label to jump to if the test is true.  */
   Operand 3: label to jump to if the test is true.  */
 
 
const char *
const char *
avr_out_sbxx_branch (rtx insn, rtx operands[])
avr_out_sbxx_branch (rtx insn, rtx operands[])
{
{
  enum rtx_code comp = GET_CODE (operands[0]);
  enum rtx_code comp = GET_CODE (operands[0]);
  int long_jump = (get_attr_length (insn) >= 4);
  int long_jump = (get_attr_length (insn) >= 4);
  int reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
  int reverse = long_jump || jump_over_one_insn_p (insn, operands[3]);
 
 
  if (comp == GE)
  if (comp == GE)
    comp = EQ;
    comp = EQ;
  else if (comp == LT)
  else if (comp == LT)
    comp = NE;
    comp = NE;
 
 
  if (reverse)
  if (reverse)
    comp = reverse_condition (comp);
    comp = reverse_condition (comp);
 
 
  if (GET_CODE (operands[1]) == CONST_INT)
  if (GET_CODE (operands[1]) == CONST_INT)
    {
    {
      if (INTVAL (operands[1]) < 0x40)
      if (INTVAL (operands[1]) < 0x40)
        {
        {
          if (comp == EQ)
          if (comp == EQ)
            output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
            output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
          else
          else
            output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
            output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
        }
        }
      else
      else
        {
        {
          output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
          output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
          if (comp == EQ)
          if (comp == EQ)
            output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
            output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
          else
          else
            output_asm_insn (AS2 (sbrc,__tmp_reg__,%2), operands);
            output_asm_insn (AS2 (sbrc,__tmp_reg__,%2), operands);
        }
        }
    }
    }
  else  /* GET_CODE (operands[1]) == REG */
  else  /* GET_CODE (operands[1]) == REG */
    {
    {
      if (GET_MODE (operands[1]) == QImode)
      if (GET_MODE (operands[1]) == QImode)
        {
        {
          if (comp == EQ)
          if (comp == EQ)
            output_asm_insn (AS2 (sbrs,%1,%2), operands);
            output_asm_insn (AS2 (sbrs,%1,%2), operands);
          else
          else
            output_asm_insn (AS2 (sbrc,%1,%2), operands);
            output_asm_insn (AS2 (sbrc,%1,%2), operands);
        }
        }
      else  /* HImode or SImode */
      else  /* HImode or SImode */
        {
        {
          static char buf[] = "sbrc %A1,0";
          static char buf[] = "sbrc %A1,0";
          int bit_nr = exact_log2 (INTVAL (operands[2])
          int bit_nr = exact_log2 (INTVAL (operands[2])
                                   & GET_MODE_MASK (GET_MODE (operands[1])));
                                   & GET_MODE_MASK (GET_MODE (operands[1])));
 
 
          buf[3] = (comp == EQ) ? 's' : 'c';
          buf[3] = (comp == EQ) ? 's' : 'c';
          buf[6] = 'A' + (bit_nr >> 3);
          buf[6] = 'A' + (bit_nr >> 3);
          buf[9] = '0' + (bit_nr & 7);
          buf[9] = '0' + (bit_nr & 7);
          output_asm_insn (buf, operands);
          output_asm_insn (buf, operands);
        }
        }
    }
    }
 
 
  if (long_jump)
  if (long_jump)
    return (AS1 (rjmp,.+4) CR_TAB
    return (AS1 (rjmp,.+4) CR_TAB
            AS1 (jmp,%3));
            AS1 (jmp,%3));
  if (!reverse)
  if (!reverse)
    return AS1 (rjmp,%3);
    return AS1 (rjmp,%3);
  return "";
  return "";
}
}
 
 
/* Worker function for TARGET_ASM_CONSTRUCTOR.  */
/* Worker function for TARGET_ASM_CONSTRUCTOR.  */
 
 
static void
static void
avr_asm_out_ctor (rtx symbol, int priority)
avr_asm_out_ctor (rtx symbol, int priority)
{
{
  fputs ("\t.global __do_global_ctors\n", asm_out_file);
  fputs ("\t.global __do_global_ctors\n", asm_out_file);
  default_ctor_section_asm_out_constructor (symbol, priority);
  default_ctor_section_asm_out_constructor (symbol, priority);
}
}
 
 
/* Worker function for TARGET_ASM_DESTRUCTOR.  */
/* Worker function for TARGET_ASM_DESTRUCTOR.  */
 
 
static void
static void
avr_asm_out_dtor (rtx symbol, int priority)
avr_asm_out_dtor (rtx symbol, int priority)
{
{
  fputs ("\t.global __do_global_dtors\n", asm_out_file);
  fputs ("\t.global __do_global_dtors\n", asm_out_file);
  default_dtor_section_asm_out_destructor (symbol, priority);
  default_dtor_section_asm_out_destructor (symbol, priority);
}
}
 
 
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 
static bool
static bool
avr_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
avr_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
{
  if (TYPE_MODE (type) == BLKmode)
  if (TYPE_MODE (type) == BLKmode)
    {
    {
      HOST_WIDE_INT size = int_size_in_bytes (type);
      HOST_WIDE_INT size = int_size_in_bytes (type);
      return (size == -1 || size > 8);
      return (size == -1 || size > 8);
    }
    }
  else
  else
    return false;
    return false;
}
}
 
 
#include "gt-avr.h"
#include "gt-avr.h"
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.