diff gcc/config/avr/avr.c @ 55:77e2b8dfacca gcc-4.4.5

update it from 4.4.3 to 4.5.0
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Fri, 12 Feb 2010 23:39:51 +0900
parents 855418dad1a3
children b7f97abdc517
line wrap: on
line diff
--- a/gcc/config/avr/avr.c	Sun Feb 07 18:28:00 2010 +0900
+++ b/gcc/config/avr/avr.c	Fri Feb 12 23:39:51 2010 +0900
@@ -1,7 +1,7 @@
 /* Subroutines for insn-output.c for ATMEL AVR micro controllers
    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008,
    2009 Free Software Foundation, Inc.
-   Contributed by Denis Chertykov (denisc@overta.ru)
+   Contributed by Denis Chertykov (chertykov@gmail.com)
 
    This file is part of GCC.
 
@@ -62,14 +62,15 @@
 static int avr_num_arg_regs (enum machine_mode, tree);
 
 static RTX_CODE compare_condition (rtx insn);
+static rtx avr_legitimize_address (rtx, rtx, enum machine_mode);
 static int compare_sign_p (rtx insn);
 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_fntype_attribute (tree *, tree, tree, int, bool *);
-const struct attribute_spec avr_attribute_table[];
 static bool avr_assemble_integer (rtx, unsigned int, int);
 static void avr_file_start (void);
 static void avr_file_end (void);
+static bool avr_legitimate_address_p (enum machine_mode, rtx, bool);
 static void avr_asm_function_end_prologue (FILE *);
 static void avr_asm_function_begin_epilogue (FILE *);
 static rtx avr_function_value (const_tree, const_tree, bool);
@@ -87,6 +88,9 @@
 static struct machine_function * avr_init_machine_status (void);
 static rtx avr_builtin_setjmp_frame_value (void);
 static bool avr_hard_regno_scratch_ok (unsigned int);
+static unsigned int avr_case_values_threshold (void);
+static bool avr_frame_pointer_required_p (void);
+static bool avr_can_eliminate (const int, const int);
 
 /* Allocate registers from r25 to r8 for parameters for function calls.  */
 #define FIRST_CUM_REG 26
@@ -100,215 +104,29 @@
 /* AVR register names {"r0", "r1", ..., "r31"} */
 static const char *const avr_regnames[] = REGISTER_NAMES;
 
-/* This holds the last insn address.  */
-static int last_insn_address = 0;
-
 /* Preprocessor macros to define depending on MCU type.  */
 const char *avr_extra_arch_macro;
 
 /* Current architecture.  */
 const struct base_arch_s *avr_current_arch;
 
+/* Current device.  */
+const struct mcu_type_s *avr_current_device;
+
 section *progmem_section;
 
-static const struct base_arch_s avr_arch_types[] = {
-  { 1, 0, 0, 0, 0, 0, 0, 0, NULL },  /* unknown device specified */
-  { 1, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1"   },
-  { 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2"   },
-  { 0, 0, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=25"  },
-  { 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=3"   },
-  { 0, 0, 1, 0, 1, 0, 0, 0, "__AVR_ARCH__=31"  },
-  { 0, 0, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=35"  },
-  { 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=4"   },
-  { 0, 1, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=5"   },
-  { 0, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=51"  },
-  { 0, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=6"   }
-};
-
-/* These names are used as the index into the avr_arch_types[] table 
-   above.  */
-
-enum avr_arch
+/* AVR attributes.  */
+static const struct attribute_spec avr_attribute_table[] =
 {
-  ARCH_UNKNOWN,
-  ARCH_AVR1,
-  ARCH_AVR2,
-  ARCH_AVR25,
-  ARCH_AVR3,
-  ARCH_AVR31,
-  ARCH_AVR35,
-  ARCH_AVR4,
-  ARCH_AVR5,
-  ARCH_AVR51,
-  ARCH_AVR6
-};
-
-struct mcu_type_s {
-  const char *const name;
-  int arch;  /* index in avr_arch_types[] */
-  /* Must lie outside user's namespace.  NULL == no macro.  */
-  const char *const macro;
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute },
+  { "signal",    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 },
+  { "OS_task",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
+  { "OS_main",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
+  { NULL,        0, 0, false, false, false, NULL }
 };
-
-/* 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?):
-    - here
-    - avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)
-    - t-avr (MULTILIB_MATCHES)
-    - gas/config/tc-avr.c
-    - avr-libc  */
-
-static const struct mcu_type_s avr_mcu_types[] = {
-    /* Classic, <= 8K.  */
-  { "avr2",         ARCH_AVR2, NULL },
-  { "at90s2313",    ARCH_AVR2, "__AVR_AT90S2313__" },
-  { "at90s2323",    ARCH_AVR2, "__AVR_AT90S2323__" },
-  { "at90s2333",    ARCH_AVR2, "__AVR_AT90S2333__" },
-  { "at90s2343",    ARCH_AVR2, "__AVR_AT90S2343__" },
-  { "attiny22",     ARCH_AVR2, "__AVR_ATtiny22__" },
-  { "attiny26",     ARCH_AVR2, "__AVR_ATtiny26__" },
-  { "at90s4414",    ARCH_AVR2, "__AVR_AT90S4414__" },
-  { "at90s4433",    ARCH_AVR2, "__AVR_AT90S4433__" },
-  { "at90s4434",    ARCH_AVR2, "__AVR_AT90S4434__" },
-  { "at90s8515",    ARCH_AVR2, "__AVR_AT90S8515__" },
-  { "at90c8534",    ARCH_AVR2, "__AVR_AT90C8534__" },
-  { "at90s8535",    ARCH_AVR2, "__AVR_AT90S8535__" },
-    /* Classic + MOVW, <= 8K.  */
-  { "avr25",        ARCH_AVR25, NULL },
-  { "ata6289",      ARCH_AVR25, "__AVR_ATA6289__" },
-  { "attiny13",     ARCH_AVR25, "__AVR_ATtiny13__" },
-  { "attiny13a",    ARCH_AVR25, "__AVR_ATtiny13A__" },
-  { "attiny2313",   ARCH_AVR25, "__AVR_ATtiny2313__" },
-  { "attiny24",     ARCH_AVR25, "__AVR_ATtiny24__" },
-  { "attiny44",     ARCH_AVR25, "__AVR_ATtiny44__" },
-  { "attiny84",     ARCH_AVR25, "__AVR_ATtiny84__" },
-  { "attiny25",     ARCH_AVR25, "__AVR_ATtiny25__" },
-  { "attiny45",     ARCH_AVR25, "__AVR_ATtiny45__" },
-  { "attiny85",     ARCH_AVR25, "__AVR_ATtiny85__" },
-  { "attiny261",    ARCH_AVR25, "__AVR_ATtiny261__" },
-  { "attiny461",    ARCH_AVR25, "__AVR_ATtiny461__" },
-  { "attiny861",    ARCH_AVR25, "__AVR_ATtiny861__" },
-  { "attiny43u",    ARCH_AVR25, "__AVR_ATtiny43U__" },
-  { "attiny87",     ARCH_AVR25, "__AVR_ATtiny87__" },
-  { "attiny48",     ARCH_AVR25, "__AVR_ATtiny48__" },
-  { "attiny88",     ARCH_AVR25, "__AVR_ATtiny88__" },
-  { "at86rf401",    ARCH_AVR25, "__AVR_AT86RF401__" },
-    /* Classic, > 8K, <= 64K.  */
-  { "avr3",         ARCH_AVR3, NULL },
-  { "at43usb355",   ARCH_AVR3, "__AVR_AT43USB355__" },
-  { "at76c711",     ARCH_AVR3, "__AVR_AT76C711__" },
-    /* Classic, == 128K.  */
-  { "avr31",        ARCH_AVR31, NULL },
-  { "atmega103",    ARCH_AVR31, "__AVR_ATmega103__" },
-  { "at43usb320",   ARCH_AVR31, "__AVR_AT43USB320__" },
-    /* Classic + MOVW + JMP/CALL.  */
-  { "avr35",        ARCH_AVR35, NULL },
-  { "at90usb82",    ARCH_AVR35, "__AVR_AT90USB82__" },
-  { "at90usb162",   ARCH_AVR35, "__AVR_AT90USB162__" },
-  { "attiny167",    ARCH_AVR35, "__AVR_ATtiny167__" },
-  { "attiny327",    ARCH_AVR35, "__AVR_ATtiny327__" },
-    /* Enhanced, <= 8K.  */
-  { "avr4",         ARCH_AVR4, NULL },
-  { "atmega8",      ARCH_AVR4, "__AVR_ATmega8__" },
-  { "atmega48",     ARCH_AVR4, "__AVR_ATmega48__" },
-  { "atmega48p",    ARCH_AVR4, "__AVR_ATmega48P__" },
-  { "atmega88",     ARCH_AVR4, "__AVR_ATmega88__" },
-  { "atmega88p",    ARCH_AVR4, "__AVR_ATmega88P__" },
-  { "atmega8515",   ARCH_AVR4, "__AVR_ATmega8515__" },
-  { "atmega8535",   ARCH_AVR4, "__AVR_ATmega8535__" },
-  { "atmega8hva",   ARCH_AVR4, "__AVR_ATmega8HVA__" },
-  { "atmega4hvd",   ARCH_AVR4, "__AVR_ATmega4HVD__" },
-  { "atmega8hvd",   ARCH_AVR4, "__AVR_ATmega8HVD__" },
-  { "atmega8c1",    ARCH_AVR4, "__AVR_ATmega8C1__" },
-  { "atmega8m1",    ARCH_AVR4, "__AVR_ATmega8M1__" },
-  { "at90pwm1",     ARCH_AVR4, "__AVR_AT90PWM1__" },
-  { "at90pwm2",     ARCH_AVR4, "__AVR_AT90PWM2__" },
-  { "at90pwm2b",    ARCH_AVR4, "__AVR_AT90PWM2B__" },
-  { "at90pwm3",     ARCH_AVR4, "__AVR_AT90PWM3__" },
-  { "at90pwm3b",    ARCH_AVR4, "__AVR_AT90PWM3B__" },
-  { "at90pwm81",    ARCH_AVR4, "__AVR_AT90PWM81__" },
-    /* Enhanced, > 8K, <= 64K.  */
-  { "avr5",         ARCH_AVR5, NULL },
-  { "atmega16",     ARCH_AVR5, "__AVR_ATmega16__" },
-  { "atmega161",    ARCH_AVR5, "__AVR_ATmega161__" },
-  { "atmega162",    ARCH_AVR5, "__AVR_ATmega162__" },
-  { "atmega163",    ARCH_AVR5, "__AVR_ATmega163__" },
-  { "atmega164p",   ARCH_AVR5, "__AVR_ATmega164P__" },
-  { "atmega165",    ARCH_AVR5, "__AVR_ATmega165__" },
-  { "atmega165p",   ARCH_AVR5, "__AVR_ATmega165P__" },
-  { "atmega168",    ARCH_AVR5, "__AVR_ATmega168__" },
-  { "atmega168p",   ARCH_AVR5, "__AVR_ATmega168P__" },
-  { "atmega169",    ARCH_AVR5, "__AVR_ATmega169__" },
-  { "atmega169p",   ARCH_AVR5, "__AVR_ATmega169P__" },
-  { "atmega32",     ARCH_AVR5, "__AVR_ATmega32__" },
-  { "atmega323",    ARCH_AVR5, "__AVR_ATmega323__" },
-  { "atmega324p",   ARCH_AVR5, "__AVR_ATmega324P__" },
-  { "atmega325",    ARCH_AVR5, "__AVR_ATmega325__" },
-  { "atmega325p",   ARCH_AVR5, "__AVR_ATmega325P__" },
-  { "atmega3250",   ARCH_AVR5, "__AVR_ATmega3250__" },
-  { "atmega3250p",  ARCH_AVR5, "__AVR_ATmega3250P__" },
-  { "atmega328p",   ARCH_AVR5, "__AVR_ATmega328P__" },
-  { "atmega329",    ARCH_AVR5, "__AVR_ATmega329__" },
-  { "atmega329p",   ARCH_AVR5, "__AVR_ATmega329P__" },
-  { "atmega3290",   ARCH_AVR5, "__AVR_ATmega3290__" },
-  { "atmega3290p",  ARCH_AVR5, "__AVR_ATmega3290P__" },
-  { "atmega406",    ARCH_AVR5, "__AVR_ATmega406__" },
-  { "atmega64",     ARCH_AVR5, "__AVR_ATmega64__" },
-  { "atmega640",    ARCH_AVR5, "__AVR_ATmega640__" },
-  { "atmega644",    ARCH_AVR5, "__AVR_ATmega644__" },
-  { "atmega644p",   ARCH_AVR5, "__AVR_ATmega644P__" },
-  { "atmega645",    ARCH_AVR5, "__AVR_ATmega645__" },
-  { "atmega6450",   ARCH_AVR5, "__AVR_ATmega6450__" },
-  { "atmega649",    ARCH_AVR5, "__AVR_ATmega649__" },
-  { "atmega6490",   ARCH_AVR5, "__AVR_ATmega6490__" },
-  { "atmega16hva",  ARCH_AVR5, "__AVR_ATmega16HVA__" },
-  { "atmega16hvb",  ARCH_AVR5, "__AVR_ATmega16HVB__" },
-  { "atmega32hvb",  ARCH_AVR5, "__AVR_ATmega32HVB__" },
-  { "at90can32",    ARCH_AVR5, "__AVR_AT90CAN32__" },
-  { "at90can64",    ARCH_AVR5, "__AVR_AT90CAN64__" },
-  { "at90pwm216",   ARCH_AVR5, "__AVR_AT90PWM216__" },
-  { "at90pwm316",   ARCH_AVR5, "__AVR_AT90PWM316__" },
-  { "atmega16c1",   ARCH_AVR5, "__AVR_ATmega16C1__" },
-  { "atmega32c1",   ARCH_AVR5, "__AVR_ATmega32C1__" },
-  { "atmega64c1",   ARCH_AVR5, "__AVR_ATmega64C1__" },
-  { "atmega16m1",   ARCH_AVR5, "__AVR_ATmega16M1__" },
-  { "atmega32m1",   ARCH_AVR5, "__AVR_ATmega32M1__" },
-  { "atmega64m1",   ARCH_AVR5, "__AVR_ATmega64M1__" },
-  { "atmega16u4",   ARCH_AVR5, "__AVR_ATmega16U4__" },
-  { "atmega32u4",   ARCH_AVR5, "__AVR_ATmega32U4__" },
-  { "atmega32u6",   ARCH_AVR5, "__AVR_ATmega32U6__" },
-  { "at90scr100",   ARCH_AVR5, "__AVR_AT90SCR100__" },
-  { "at90usb646",   ARCH_AVR5, "__AVR_AT90USB646__" },
-  { "at90usb647",   ARCH_AVR5, "__AVR_AT90USB647__" },
-  { "at94k",        ARCH_AVR5, "__AVR_AT94K__" },
-    /* Enhanced, == 128K.  */
-  { "avr51",        ARCH_AVR51, NULL },
-  { "atmega128",    ARCH_AVR51, "__AVR_ATmega128__" },
-  { "atmega1280",   ARCH_AVR51, "__AVR_ATmega1280__" },
-  { "atmega1281",   ARCH_AVR51, "__AVR_ATmega1281__" },
-  { "atmega1284p",  ARCH_AVR51, "__AVR_ATmega1284P__" },
-  { "atmega128rfa1",  ARCH_AVR51, "__AVR_ATmega128RFA1__" },
-  { "at90can128",   ARCH_AVR51, "__AVR_AT90CAN128__" },
-  { "at90usb1286",  ARCH_AVR51, "__AVR_AT90USB1286__" },
-  { "at90usb1287",  ARCH_AVR51, "__AVR_AT90USB1287__" },
-  { "m3000f",       ARCH_AVR51, "__AVR_M3000F__" },
-  { "m3000s",       ARCH_AVR51, "__AVR_M3000S__" },
-  { "m3001b",       ARCH_AVR51, "__AVR_M3001B__" },
-    /* 3-Byte PC.  */
-  { "avr6",         ARCH_AVR6, NULL },
-  { "atmega2560",   ARCH_AVR6, "__AVR_ATmega2560__" },
-  { "atmega2561",   ARCH_AVR6, "__AVR_ATmega2561__" },
-    /* Assembler only.  */
-  { "avr1",         ARCH_AVR1, NULL },
-  { "at90s1200",    ARCH_AVR1, "__AVR_AT90S1200__" },
-  { "attiny11",     ARCH_AVR1, "__AVR_ATtiny11__" },
-  { "attiny12",     ARCH_AVR1, "__AVR_ATtiny12__" },
-  { "attiny15",     ARCH_AVR1, "__AVR_ATtiny15__" },
-  { "attiny28",     ARCH_AVR1, "__AVR_ATtiny28__" },
-  { NULL,           ARCH_UNKNOWN, NULL }
-};
-
-int avr_case_values_threshold = 30000;
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
@@ -349,6 +167,9 @@
 #undef TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG avr_reorg
 
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS avr_legitimize_address
+
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY avr_return_in_memory
 
@@ -360,6 +181,16 @@
 
 #undef TARGET_HARD_REGNO_SCRATCH_OK
 #define TARGET_HARD_REGNO_SCRATCH_OK avr_hard_regno_scratch_ok
+#undef TARGET_CASE_VALUES_THRESHOLD
+#define TARGET_CASE_VALUES_THRESHOLD avr_case_values_threshold
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P avr_legitimate_address_p
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED avr_frame_pointer_required_p
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE avr_can_eliminate
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
@@ -367,13 +198,9 @@
 avr_override_options (void)
 {
   const struct mcu_type_s *t;
-  static bool warned_no_tablejump_deprecated = false;
 
   flag_delete_null_pointer_checks = 0;
 
-  if (!PARAM_SET_P (PARAM_INLINE_CALL_COST))
-    set_param_value ("inline-call-cost", 5);
-
   for (t = avr_mcu_types; t->name; t++)
     if (strcmp (t->name, avr_mcu_name) == 0)
       break;
@@ -386,21 +213,9 @@
 	fprintf (stderr,"   %s\n", t->name);
     }
 
-  avr_current_arch = &avr_arch_types[t->arch];
-  avr_extra_arch_macro = t->macro;
-
-  if (optimize && !TARGET_NO_TABLEJUMP)
-    avr_case_values_threshold = 
-      (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
-
-  if (TARGET_NO_TABLEJUMP
-      && !warned_no_tablejump_deprecated)
-    {
-      inform (input_location, "the -mno-tablejump switch is deprecated");
-      inform (input_location, "GCC 4.4 is the last release with this switch");
-      inform (input_location, "use the -fno-jump-tables switch instead");
-      warned_no_tablejump_deprecated = true;
-    }
+  avr_current_device = t;
+  avr_current_arch = &avr_arch_types[avr_current_device->arch];
+  avr_extra_arch_macro = avr_current_device->macro;
 
   tmp_reg_rtx  = gen_rtx_REG (QImode, TMP_REGNO);
   zero_reg_rtx = gen_rtx_REG (QImode, ZERO_REGNO);
@@ -410,7 +225,7 @@
 
 /*  return register class from register number.  */
 
-static const int reg_class_tab[]={
+static const enum reg_class 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,
@@ -522,9 +337,6 @@
   int int_or_sig_p = (interrupt_function_p (current_function_decl)
 		      || signal_function_p (current_function_decl));
 
-  if (!reload_completed)
-    cfun->machine->is_leaf = leaf_function_p ();
-
   if (set)
     CLEAR_HARD_REG_SET (*set);
   count = 0;
@@ -543,7 +355,7 @@
       if (fixed_regs[reg])
 	continue;
 
-      if ((int_or_sig_p && !cfun->machine->is_leaf && call_used_regs[reg])
+      if ((int_or_sig_p && !current_function_is_leaf && call_used_regs[reg])
 	  || (df_regs_ever_live_p (reg)
 	      && (int_or_sig_p || !call_used_regs[reg])
 	      && !(frame_pointer_needed
@@ -557,10 +369,21 @@
   return count;
 }
 
+/* Return true if register FROM can be eliminated via register TO.  */
+
+bool
+avr_can_eliminate (const int from, const int to)
+{
+  return ((from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+	  || ((from == FRAME_POINTER_REGNUM 
+	       || from == FRAME_POINTER_REGNUM + 1)
+	      && !frame_pointer_needed));
+}
+
 /* Compute offset between arg_pointer and frame_pointer.  */
 
 int
-initial_elimination_offset (int from, int to)
+avr_initial_elimination_offset (int from, int to)
 {
   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return 0;
@@ -585,6 +408,31 @@
 			 gen_int_mode (STARTING_FRAME_OFFSET, Pmode));
 }
 
+/* Return contents of MEM at frame pointer + stack size + 1 (+2 if 3 byte PC).
+   This is return address of function.  */
+rtx 
+avr_return_addr_rtx (int count, const_rtx tem)
+{
+  rtx r;
+    
+  /* Can only return this functions return address. Others not supported.  */
+  if (count)
+     return NULL;
+
+  if (AVR_3_BYTE_PC)
+    {
+      r = gen_rtx_SYMBOL_REF (Pmode, ".L__stack_usage+2");
+      warning (0, "'builtin_return_address' contains only 2 bytes of address");
+    }
+  else
+    r = gen_rtx_SYMBOL_REF (Pmode, ".L__stack_usage+1");
+
+  r = gen_rtx_PLUS (Pmode, tem, r);
+  r = gen_frame_mem (Pmode, memory_address (Pmode, r));
+  r = gen_rtx_ROTATE (HImode, r, GEN_INT (8));
+  return  r;
+}
+
 /* Return 1 if the function epilogue is just a single "ret".  */
 
 int
@@ -677,8 +525,6 @@
   rtx pushword = gen_rtx_MEM (HImode,
                   gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
   rtx insn;
-
-  last_insn_address = 0;
   
   /* Init cfun->machine.  */
   cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
@@ -686,6 +532,7 @@
   cfun->machine->is_signal = signal_function_p (current_function_decl);
   cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl);
   cfun->machine->is_OS_main = avr_OS_main_function_p (current_function_decl);
+  cfun->machine->stack_usage = 0;
   
   /* Prologue: naked.  */
   if (cfun->machine->is_naked)
@@ -714,10 +561,12 @@
       /* Push zero reg.  */
       insn = emit_move_insn (pushbyte, zero_reg_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+      cfun->machine->stack_usage++;
 
       /* Push tmp reg.  */
       insn = emit_move_insn (pushbyte, tmp_reg_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+      cfun->machine->stack_usage++;
 
       /* Push SREG.  */
       insn = emit_move_insn (tmp_reg_rtx, 
@@ -725,6 +574,7 @@
       RTX_FRAME_RELATED_P (insn) = 1;
       insn = emit_move_insn (pushbyte, tmp_reg_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
+      cfun->machine->stack_usage++;
 
       /* Push RAMPZ.  */
       if(AVR_HAVE_RAMPZ 
@@ -735,6 +585,7 @@
           RTX_FRAME_RELATED_P (insn) = 1;
           insn = emit_move_insn (pushbyte, tmp_reg_rtx);
           RTX_FRAME_RELATED_P (insn) = 1;
+          cfun->machine->stack_usage++;
         }
 	
       /* Clear zero reg.  */
@@ -756,6 +607,7 @@
         emit_insn (gen_call_prologue_saves (gen_int_mode (live_seq, HImode),
 					    gen_int_mode (size + live_seq, HImode)));
       RTX_FRAME_RELATED_P (insn) = 1;
+      cfun->machine->stack_usage += size + live_seq;
     }
   else
     {
@@ -767,6 +619,7 @@
               /* Emit push of register to save.  */
               insn=emit_move_insn (pushbyte, gen_rtx_REG (QImode, reg));
               RTX_FRAME_RELATED_P (insn) = 1;
+              cfun->machine->stack_usage++;
             }
         }
       if (frame_pointer_needed)
@@ -776,6 +629,7 @@
               /* Push frame pointer.  */
 	      insn = emit_move_insn (pushword, frame_pointer_rtx);
               RTX_FRAME_RELATED_P (insn) = 1;
+	      cfun->machine->stack_usage += 2;
 	    }
 
           if (!size)
@@ -800,7 +654,7 @@
 	      rtx fp_plus_insns; 
 	      rtx sp_plus_insns = NULL_RTX;
 
-              if (TARGET_TINY_STACK)
+              if (AVR_HAVE_8BIT_SP)
                 {
                   /* The high byte (r29) doesn't change - prefer 'subi' (1 cycle)
                      over 'sbiw' (2 cycles, same size).  */
@@ -826,7 +680,7 @@
               RTX_FRAME_RELATED_P (insn) = 1;
 
 	      /* Copy to stack pointer.  */
-	      if (TARGET_TINY_STACK)
+	      if (AVR_HAVE_8BIT_SP)
 		{
 		  insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
 		  RTX_FRAME_RELATED_P (insn) = 1;
@@ -882,6 +736,7 @@
 		emit_insn (sp_plus_insns);
               else
 		emit_insn (fp_plus_insns);
+	      cfun->machine->stack_usage += size;
             }
         }
     }
@@ -911,6 +766,11 @@
     }
   fprintf (file, "/* frame size = " HOST_WIDE_INT_PRINT_DEC " */\n",
                  get_frame_size());
+  fprintf (file, "/* stack size = %d */\n",
+                 cfun->machine->stack_usage);
+  /* Create symbol stack offset here so all functions have it. Add 1 to stack
+     usage for offset so that SP + .L__stack_offset = return address.  */
+  fprintf (file, ".L__stack_usage = %d\n", cfun->machine->stack_usage);
 }
 
 
@@ -980,7 +840,7 @@
 	      rtx fp_plus_insns;
 	      rtx sp_plus_insns = NULL_RTX;
 	      
-	      if (TARGET_TINY_STACK)
+	      if (AVR_HAVE_8BIT_SP)
                 {
                   /* The high byte (r29) doesn't change - prefer 'subi' 
                      (1 cycle) over 'sbiw' (2 cycles, same size).  */
@@ -1001,7 +861,7 @@
 							  GET_MODE(myfp))));
 
 	      /* Copy to stack pointer.  */
-	      if (TARGET_TINY_STACK)
+	      if (AVR_HAVE_8BIT_SP)
 		{
 		  emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
 		}
@@ -1096,8 +956,8 @@
 /* Return nonzero if X (an RTX) is a legitimate memory address on the target
    machine for a memory operand of mode MODE.  */
 
-int
-legitimate_address_p (enum machine_mode mode, rtx x, int strict)
+bool
+avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
   enum reg_class r = NO_REGS;
   
@@ -1165,7 +1025,7 @@
    memory address for an operand of mode MODE  */
 
 rtx
-legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
+avr_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
 {
   x = oldx;
   if (TARGET_ALL_DEBUG)
@@ -1263,12 +1123,33 @@
 
     default:
       if (CONSTANT_ADDRESS_P (addr)
-	  && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (addr))
-	      || GET_CODE (addr) == LABEL_REF))
+	  && text_segment_operand (addr, VOIDmode))
 	{
-	  fprintf (file, "gs(");
-	  output_addr_const (file,addr);
-	  fprintf (file ,")");
+	  rtx x = XEXP (addr,0);
+	  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x,1)) == CONST_INT)
+	    {
+	      /* Assembler gs() will implant word address. Make offset 
+		 a byte offset inside gs() for assembler. This is 
+		 needed because the more logical (constant+gs(sym)) is not 
+		 accepted by gas. For 128K and lower devices this is ok. For
+		 large devices it will create a Trampoline to offset from symbol 
+		 which may not be what the user really wanted.  */
+	      fprintf (file, "gs(");
+	      output_addr_const (file, XEXP (x,0));
+	      fprintf (file,"+" HOST_WIDE_INT_PRINT_DEC ")", 2 * INTVAL (XEXP (x,1)));
+	      if (AVR_3_BYTE_PC)
+	        if (warning ( 0, "Pointer offset from symbol maybe incorrect."))
+		  {
+		    output_addr_const (stderr, addr);
+		    fprintf(stderr,"\n");
+		  }
+	    }
+	  else
+	    {
+	      fprintf (file, "gs(");
+	      output_addr_const (file, addr);
+	      fprintf (file, ")");
+	    }
 	}
       else
 	output_addr_const (file, addr);
@@ -1308,12 +1189,18 @@
   else if (GET_CODE (x) == MEM)
     {
       rtx addr = XEXP (x,0);
-
-      if (CONSTANT_P (addr) && abcd)
+      if (code == 'm')
 	{
-	  fputc ('(', file);
-	  output_address (addr);
-	  fprintf (file, ")+%d", abcd);
+	   if (!CONSTANT_P (addr))
+	    fatal_insn ("bad address, not a constant):", addr);
+	  /* Assembler template with m-code is data - not progmem section */
+	  if (text_segment_operand (addr, VOIDmode))
+	    if (warning ( 0, "accessing data memory with program memory address"))
+	      {
+		output_addr_const (stderr, addr);
+		fprintf(stderr,"\n");
+	      }
+	  output_addr_const (file, addr);
 	}
       else if (code == 'o')
 	{
@@ -1344,6 +1231,18 @@
       else
 	print_operand_address (file, addr);
     }
+  else if (code == 'x')
+    {
+      /* Constant progmem address - like used in jmp or call */
+      if (0 == text_segment_operand (x, VOIDmode))
+	    if (warning ( 0, "accessing program  memory with data memory address"))
+	  {
+	    output_addr_const (stderr, x);
+	    fprintf(stderr,"\n");
+	  }
+      /* Use normal symbol for direct address no linker trampoline needed */
+      output_addr_const (file, x);
+    }
   else if (GET_CODE (x) == CONST_DOUBLE)
     {
       long val;
@@ -1454,7 +1353,7 @@
 int
 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_CODE (x) == LABEL_REF
 					    ? XEXP (x, 0) : x));
   int cur_addr = INSN_ADDRESSES (INSN_UID (insn));
   int jump_distance = cur_addr - dest_addr;
@@ -1580,25 +1479,17 @@
           && INTVAL (op) <= 0xff && INTVAL (op) >= 0);
 }
 
-/* Output all insn addresses and their sizes into the assembly language
-   output file.  This is helpful for debugging whether the length attributes
-   in the md file are correct.
-   Output insn cost for next insn.  */
+/* Output insn cost for next insn.  */
 
 void
 final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED,
 		    int num_operands ATTRIBUTE_UNUSED)
 {
-  int uid = INSN_UID (insn);
-
-  if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG)
+  if (TARGET_ALL_DEBUG)
     {
-      fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n",
-	       INSN_ADDRESSES (uid),
-               INSN_ADDRESSES (uid) - last_insn_address,
+      fprintf (asm_out_file, "/* DEBUG: cost = %d.  */\n",
 	       rtx_cost (PATTERN (insn), INSN, !optimize_size));
     }
-  last_insn_address = INSN_ADDRESSES (uid);
 }
 
 /* Return 0 if undefined, 1 if always true or always false.  */
@@ -1814,7 +1705,7 @@
 	{
 	  if (test_hard_reg_class (STACK_REG, dest))
 	    {
-	      if (TARGET_TINY_STACK)
+	      if (AVR_HAVE_8BIT_SP)
 		return *l = 1, AS2 (out,__SP_L__,%A1);
               /* Use simple load of stack pointer if no interrupts are 
 		 used.  */
@@ -1969,10 +1860,10 @@
       if (optimize > 0 && io_address_operand (x, QImode))
 	{
 	  *l = 1;
-	  return AS2 (in,%0,%1-0x20);
+	  return AS2 (in,%0,%m1-0x20);
 	}
       *l = 2;
-      return AS2 (lds,%0,%1);
+      return AS2 (lds,%0,%m1);
     }
   /* memory access by reg+disp */
   else if (GET_CODE (x) == PLUS
@@ -2157,12 +2048,12 @@
       if (optimize > 0 && io_address_operand (base, HImode))
 	{
 	  *l = 2;
-	  return (AS2 (in,%A0,%A1-0x20) CR_TAB
-		  AS2 (in,%B0,%B1-0x20));
+	  return (AS2 (in,%A0,%m1-0x20) CR_TAB
+		  AS2 (in,%B0,%m1+1-0x20));
 	}
       *l = 4;
-      return (AS2 (lds,%A0,%A1) CR_TAB
-	      AS2 (lds,%B0,%B1));
+      return (AS2 (lds,%A0,%m1) CR_TAB
+	      AS2 (lds,%B0,%m1+1));
     }
   
   fatal_insn ("unknown move insn:",insn);
@@ -2321,10 +2212,10 @@
 		  AS2 (ld,%C0,%1) CR_TAB
 		  AS2 (ld,%D0,%1));
   else if (CONSTANT_ADDRESS_P (base))
-      return *l=8, (AS2 (lds,%A0,%A1) CR_TAB
-		    AS2 (lds,%B0,%B1) CR_TAB
-		    AS2 (lds,%C0,%C1) CR_TAB
-		    AS2 (lds,%D0,%D1));
+      return *l=8, (AS2 (lds,%A0,%m1) CR_TAB
+		    AS2 (lds,%B0,%m1+1) CR_TAB
+		    AS2 (lds,%C0,%m1+2) CR_TAB
+		    AS2 (lds,%D0,%m1+3));
     
   fatal_insn ("unknown move insn:",insn);
   return "";
@@ -2344,10 +2235,10 @@
     l = &tmp;
   
   if (CONSTANT_ADDRESS_P (base))
-    return *l=8,(AS2 (sts,%A0,%A1) CR_TAB
-		 AS2 (sts,%B0,%B1) CR_TAB
-		 AS2 (sts,%C0,%C1) CR_TAB
-		 AS2 (sts,%D0,%D1));
+    return *l=8,(AS2 (sts,%m0,%A1) CR_TAB
+		 AS2 (sts,%m0+1,%B1) CR_TAB
+		 AS2 (sts,%m0+2,%C1) CR_TAB
+		 AS2 (sts,%m0+3,%D1));
   if (reg_base > 0)                 /* (r) */
     {
       if (reg_base == REG_X)                /* (R26) */
@@ -2657,10 +2548,10 @@
       if (optimize > 0 && io_address_operand (x, QImode))
 	{
 	  *l = 1;
-	  return AS2 (out,%0-0x20,%1);
+	  return AS2 (out,%m0-0x20,%1);
 	}
       *l = 2;
-      return AS2 (sts,%0,%1);
+      return AS2 (sts,%m0,%1);
     }
   /* memory access by reg+disp */
   else if (GET_CODE (x) == PLUS	
@@ -2736,11 +2627,11 @@
       if (optimize > 0 && io_address_operand (base, HImode))
 	{
 	  *l = 2;
-	  return (AS2 (out,%B0-0x20,%B1) CR_TAB
-		  AS2 (out,%A0-0x20,%A1));
+	  return (AS2 (out,%m0+1-0x20,%B1) CR_TAB
+		  AS2 (out,%m0-0x20,%A1));
 	}
-      return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
-		      AS2 (sts,%A0,%A1));
+      return *l = 4, (AS2 (sts,%m0+1,%B1) CR_TAB
+		      AS2 (sts,%m0,%A1));
     }
   if (reg_base > 0)
     {
@@ -2855,8 +2746,8 @@
 
 /* Return 1 if frame pointer for current function required.  */
 
-int
-frame_pointer_required_p (void)
+bool
+avr_frame_pointer_required_p (void)
 {
   return (cfun->calls_alloca
 	  || crtl->args.info.nregs == 0
@@ -2912,21 +2803,21 @@
 /* Output test instruction for HImode.  */
 
 const char *
-out_tsthi (rtx insn, int *l)
+out_tsthi (rtx insn, rtx op, int *l)
 {
   if (compare_sign_p (insn))
     {
       if (l) *l = 1;
       return AS1 (tst,%B0);
     }
-  if (reg_unused_after (insn, SET_SRC (PATTERN (insn)))
+  if (reg_unused_after (insn, op)
       && compare_eq_p (insn))
     {
       /* Faster than sbiw if we can clobber the operand.  */
       if (l) *l = 1;
-      return AS2 (or,%A0,%B0);
+      return "or %A0,%B0";
     }
-  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
+  if (test_hard_reg_class (ADDW_REGS, op))
     {
       if (l) *l = 1;
       return AS2 (sbiw,%0,0);
@@ -2940,14 +2831,14 @@
 /* Output test instruction for SImode.  */
 
 const char *
-out_tstsi (rtx insn, int *l)
+out_tstsi (rtx insn, rtx op, int *l)
 {
   if (compare_sign_p (insn))
     {
       if (l) *l = 1;
       return AS1 (tst,%D0);
     }
-  if (test_hard_reg_class (ADDW_REGS, SET_SRC (PATTERN (insn))))
+  if (test_hard_reg_class (ADDW_REGS, op))
     {
       if (l) *l = 3;
       return (AS2 (sbiw,%A0,0) CR_TAB
@@ -3247,9 +3138,9 @@
 	      return (AS1 (swap,%A0)    CR_TAB
 		      AS1 (swap,%B0)    CR_TAB
 		      AS2 (ldi,%3,0xf0) CR_TAB
-		      AS2 (and,%B0,%3)  CR_TAB
+		      "and %B0,%3"      CR_TAB
 		      AS2 (eor,%B0,%A0) CR_TAB
-		      AS2 (and,%A0,%3)  CR_TAB
+		      "and %A0,%3"      CR_TAB
 		      AS2 (eor,%B0,%A0));
 	    }
 	  break;  /* optimize_size ? 6 : 8 */
@@ -3277,9 +3168,9 @@
 		      AS1 (swap,%A0)    CR_TAB
 		      AS1 (swap,%B0)    CR_TAB
 		      AS2 (ldi,%3,0xf0) CR_TAB
-		      AS2 (and,%B0,%3)  CR_TAB
+		      "and %B0,%3"      CR_TAB
 		      AS2 (eor,%B0,%A0) CR_TAB
-		      AS2 (and,%A0,%3)  CR_TAB
+		      "and %A0,%3"      CR_TAB
 		      AS2 (eor,%B0,%A0));
 	    }
 	  break;  /* 10 */
@@ -3347,7 +3238,7 @@
 		      AS1 (clr,%A0)     CR_TAB
 		      AS1 (swap,%B0)    CR_TAB
 		      AS2 (ldi,%3,0xf0) CR_TAB
-		      AS2 (and,%B0,%3));
+		      "and %B0,%3");
 	    }
 	  *len = 6;
 	  return (AS2 (mov,%B0,%A0) CR_TAB
@@ -3386,7 +3277,7 @@
 		      AS1 (swap,%B0)    CR_TAB
 		      AS1 (lsl,%B0)     CR_TAB
 		      AS2 (ldi,%3,0xe0) CR_TAB
-		      AS2 (and,%B0,%3));
+		      "and %B0,%3");
 	    }
 	  if (AVR_HAVE_MUL)
 	    {
@@ -4024,9 +3915,9 @@
 	      return (AS1 (swap,%B0)    CR_TAB
 		      AS1 (swap,%A0)    CR_TAB
 		      AS2 (ldi,%3,0x0f) CR_TAB
-		      AS2 (and,%A0,%3)  CR_TAB
+		      "and %A0,%3"      CR_TAB
 		      AS2 (eor,%A0,%B0) CR_TAB
-		      AS2 (and,%B0,%3)  CR_TAB
+		      "and %B0,%3"      CR_TAB
 		      AS2 (eor,%A0,%B0));
 	    }
 	  break;  /* optimize_size ? 6 : 8 */
@@ -4054,9 +3945,9 @@
 		      AS1 (swap,%B0)    CR_TAB
 		      AS1 (swap,%A0)    CR_TAB
 		      AS2 (ldi,%3,0x0f) CR_TAB
-		      AS2 (and,%A0,%3)  CR_TAB
+		      "and %A0,%3"      CR_TAB
 		      AS2 (eor,%A0,%B0) CR_TAB
-		      AS2 (and,%B0,%3)  CR_TAB
+		      "and %B0,%3"      CR_TAB
 		      AS2 (eor,%A0,%B0));
 	    }
 	  break;  /* 10 */
@@ -4124,7 +4015,7 @@
 		      AS1 (clr,%B0)     CR_TAB
 		      AS1 (swap,%A0)    CR_TAB
 		      AS2 (ldi,%3,0x0f) CR_TAB
-		      AS2 (and,%A0,%3));
+		      "and %A0,%3");
 	    }
 	  *len = 6;
 	  return (AS2 (mov,%A0,%B0) CR_TAB
@@ -4163,7 +4054,7 @@
 		      AS1 (swap,%A0)    CR_TAB
 		      AS1 (lsr,%A0)     CR_TAB
 		      AS2 (ldi,%3,0x07) CR_TAB
-		      AS2 (and,%A0,%3));
+		      "and %A0,%3");
 	    }
 	  if (AVR_HAVE_MUL)
 	    {
@@ -4364,8 +4255,8 @@
 	{
 	  switch (GET_MODE (op[1]))
 	    {
-	    case HImode: out_tsthi (insn,&len); break;
-	    case SImode: out_tstsi (insn,&len); break;
+	    case HImode: out_tsthi (insn, op[1], &len); break;
+	    case SImode: out_tstsi (insn, op[1], &len); break;
 	    default: break;
 	    }
 	}
@@ -4597,8 +4488,7 @@
 avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
   if (size == POINTER_SIZE / BITS_PER_UNIT && aligned_p
-      && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
-	  || GET_CODE (x) == LABEL_REF))
+      && text_segment_operand (x, VOIDmode) )
     {
       fputs ("\t.word\tgs(", asm_out_file);
       output_addr_const (asm_out_file, x);
@@ -4739,7 +4629,7 @@
    assigned to registers of class CLASS would likely be spilled
    because registers of CLASS are needed for spill registers.  */
 
-enum reg_class
+bool
 class_likely_spilled_p (int c)
 {
   return (c != ALL_REGS && c != ADDW_REGS);
@@ -4755,18 +4645,6 @@
 
    Only `progmem' attribute valid for type.  */
 
-const struct attribute_spec avr_attribute_table[] =
-{
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute },
-  { "signal",    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 },
-  { "OS_task",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
-  { "OS_main",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
-  { NULL,        0, 0, false, false, false, NULL }
-};
-
 /* Handle a "progmem" attribute; arguments as in
    struct attribute_spec.handler.  */
 static tree
@@ -4801,8 +4679,8 @@
 	}
       else
 	{
-	  warning (OPT_Wattributes, "%qs attribute ignored",
-		   IDENTIFIER_POINTER (name));
+	  warning (OPT_Wattributes, "%qE attribute ignored",
+		   name);
 	  *no_add_attrs = true;
 	}
     }
@@ -4821,8 +4699,8 @@
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-	       IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
       *no_add_attrs = true;
     }
 
@@ -4837,8 +4715,8 @@
 {
   if (TREE_CODE (*node) != FUNCTION_TYPE)
     {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-	       IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
       *no_add_attrs = true;
     }
 
@@ -5063,9 +4941,10 @@
    case, *TOTAL contains the cost result.  */
 
 static bool
-avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
+avr_rtx_costs (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED, int *total,
 	       bool speed)
 {
+  enum rtx_code code = (enum rtx_code) codearg;
   enum machine_mode mode = GET_MODE (x);
   HOST_WIDE_INT val;
 
@@ -5731,6 +5610,21 @@
 		  XEXP (pattern,1) = x;
 		  INSN_CODE (next) = -1;
 		}
+	      else if (true_regnum (XEXP (pattern, 0)) >= 0
+		       && XEXP (pattern, 1) == const0_rtx)
+	        {
+	          /* This is a tst insn, we can reverse it.  */
+	          rtx next = next_real_insn (insn);
+	          rtx pat = PATTERN (next);
+	          rtx src = SET_SRC (pat);
+	          rtx t = XEXP (src,0);
+    
+	          PUT_CODE (t, swap_condition (GET_CODE (t)));
+	          XEXP (pattern, 1) = XEXP (pattern, 0);
+	          XEXP (pattern, 0) = const0_rtx;
+	          INSN_CODE (next) = -1;
+	          INSN_CODE (insn) = -1;
+	        }
 	      else if (true_regnum (XEXP (pattern,0)) >= 0
 		       && GET_CODE (XEXP (pattern,1)) == CONST_INT)
 		{
@@ -5750,20 +5644,6 @@
 		    }
 		}
 	    }
-	  else if (true_regnum (SET_SRC (pattern)) >= 0)
-	    {
-	      /* This is a tst insn */
-	      rtx next = next_real_insn (insn);
-	      rtx pat = PATTERN (next);
-	      rtx src = SET_SRC (pat);
-	      rtx t = XEXP (src,0);
-
-	      PUT_CODE (t, swap_condition (GET_CODE (t)));
-	      SET_SRC (pattern) = gen_rtx_COMPARE (GET_MODE (SET_SRC (pattern)), const0_rtx,
-					       SET_SRC (pattern));
-	      INSN_CODE (next) = -1;
-	      INSN_CODE (insn) = -1;
-	    }
 	}
     }
 }
@@ -6021,12 +5901,12 @@
   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, SI or DImode)
    or memory location in the I/O space (QImode only).
 
    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 2: bit number (for QImode operand) or mask (HImode, SImode).
+   Operand 2: bit number.
    Operand 3: label to jump to if the test is true.  */
 
 const char *
@@ -6049,13 +5929,13 @@
       if (INTVAL (operands[1]) < 0x40)
 	{
 	  if (comp == EQ)
-	    output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
+	    output_asm_insn (AS2 (sbis,%m1-0x20,%2), operands);
 	  else
-	    output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
+	    output_asm_insn (AS2 (sbic,%m1-0x20,%2), operands);
 	}
       else
 	{
-	  output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
+	  output_asm_insn (AS2 (in,__tmp_reg__,%m1-0x20), operands);
 	  if (comp == EQ)
 	    output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
 	  else
@@ -6074,9 +5954,7 @@
       else  /* HImode or SImode */
 	{
 	  static char buf[] = "sbrc %A1,0";
-	  int bit_nr = exact_log2 (INTVAL (operands[2])
-				   & GET_MODE_MASK (GET_MODE (operands[1])));
-
+	  int bit_nr = INTVAL (operands[2]);
 	  buf[3] = (comp == EQ) ? 's' : 'c';
 	  buf[6] = 'A' + (bit_nr >> 3);
 	  buf[9] = '0' + (bit_nr & 7);
@@ -6086,9 +5964,9 @@
 
   if (long_jump)
     return (AS1 (rjmp,.+4) CR_TAB
-	    AS1 (jmp,%3));
+	    AS1 (jmp,%x3));
   if (!reverse)
-    return AS1 (rjmp,%3);
+    return AS1 (rjmp,%x3);
   return "";
 }
 
@@ -6124,4 +6002,11 @@
     return false;
 }
 
+/* Worker function for CASE_VALUES_THRESHOLD.  */
+
+unsigned int avr_case_values_threshold (void)
+{
+  return (!AVR_HAVE_JMP_CALL || TARGET_CALL_PROLOGUES) ? 8 : 17;
+}
+
 #include "gt-avr.h"