]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/m68hc11/m68hc11.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / m68hc11 / m68hc11.c
index 87cc7c40e38ebb2bfaed2a63da85177c7f542004..4fba4a39a1ceb09ed78e231fff7203bc1be49f8a 100644 (file)
@@ -1,23 +1,23 @@
 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
-   Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
    Contributed by Stephane Carrez (stcarrez@nerim.fr)
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC 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
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
-GNU CC 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
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.
 
 Note:
    A first 68HC11 port was made by Otto Lind (otto@coactive.com)
@@ -35,6 +35,8 @@ Note:
 #include <stdio.h>
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "tm_p.h"
@@ -48,6 +50,7 @@ Note:
 #include "flags.h"
 #include "recog.h"
 #include "expr.h"
+#include "libfuncs.h"
 #include "toplev.h"
 #include "basic-block.h"
 #include "function.h"
@@ -55,30 +58,37 @@ Note:
 #include "reload.h"
 #include "target.h"
 #include "target-def.h"
-
-static void print_options PARAMS ((FILE *));
-static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
-static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
-static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
-static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
-                                                     int));
-static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
-static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
-static int must_parenthesize PARAMS ((rtx));
-static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
-static int m68hc11_auto_inc_p PARAMS ((rtx));
-static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
+#include "df.h"
+
+static void emit_move_after_reload (rtx, rtx, rtx);
+static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
+static void m68hc11_emit_logical (enum machine_mode, int, rtx *);
+static void m68hc11_reorg (void);
+static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);
+static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
+static int must_parenthesize (rtx);
+static int m68hc11_address_cost (rtx, bool);
+static int m68hc11_shift_cost (enum machine_mode, rtx, int);
+static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
+static bool m68hc11_rtx_costs (rtx, int, int, int *, bool);
+static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
 const struct attribute_spec m68hc11_attribute_table[];
 
-void create_regs_rtx PARAMS ((void));
-static void m68hc11_add_gc_roots PARAMS ((void));
-
-static void asm_print_register PARAMS ((FILE *, int));
-static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
-static void m68hc11_asm_out_constructor PARAMS ((rtx, int));
-static void m68hc11_asm_out_destructor PARAMS ((rtx, int));
-
-rtx m68hc11_soft_tmp_reg;
+void create_regs_rtx (void);
+
+static void asm_print_register (FILE *, int);
+static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
+static void m68hc11_asm_out_constructor (rtx, int);
+static void m68hc11_asm_out_destructor (rtx, int);
+static void m68hc11_file_start (void);
+static void m68hc11_encode_section_info (tree, rtx, int);
+static const char *m68hc11_strip_name_encoding (const char* str);
+static unsigned int m68hc11_section_type_flags (tree, const char*, int);
+static int autoinc_mode (rtx);
+static int m68hc11_make_autoinc_notes (rtx *, void *);
+static void m68hc11_init_libfuncs (void);
+static rtx m68hc11_struct_value_rtx (tree, int);
+static bool m68hc11_return_in_memory (const_tree, const_tree);
 
 /* Must be set to 1 to produce debug messages.  */
 int debug_m6811 = 0;
@@ -88,11 +98,12 @@ extern FILE *asm_out_file;
 rtx ix_reg;
 rtx iy_reg;
 rtx d_reg;
-rtx da_reg;
-rtx stack_push_word;
-rtx stack_pop_word;
+rtx m68hc11_soft_tmp_reg;
+static GTY(()) rtx stack_push_word;
+static GTY(()) rtx stack_pop_word;
+static GTY(()) rtx z_reg;
+static GTY(()) rtx z_reg_qi;
 static int regs_inited = 0;
-static rtx z_reg;
 
 /* Set to 1 by expand_prologue() when the function is an interrupt handler.  */
 int current_function_interrupt;
@@ -100,6 +111,10 @@ int current_function_interrupt;
 /* Set to 1 by expand_prologue() when the function is a trap handler.  */
 int current_function_trap;
 
+/* Set to 1 when the current function is placed in 68HC12 banked
+   memory and must return with rtc.  */
+int current_function_far;
+
 /* Min offset that is valid for the indirect addressing mode.  */
 HOST_WIDE_INT m68hc11_min_offset = 0;
 
@@ -124,6 +139,9 @@ unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
    This is 1 for 68HC11 and 0 for 68HC12.  */
 int m68hc11_sp_correction;
 
+int m68hc11_addr_mode;
+int m68hc11_mov_addr_mode;
+
 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns.  */
 rtx m68hc11_compare_op0;
 rtx m68hc11_compare_op1;
@@ -200,14 +218,6 @@ static const struct processor_costs m6812_cost = {
   /* divSI */
   COSTS_N_INSNS (100)
 };
-
-/* Machine specific options */
-
-const char *m68hc11_regparm_string;
-const char *m68hc11_reg_alloc_order;
-const char *m68hc11_soft_reg_count;
-
-static int nb_soft_regs;
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -219,13 +229,46 @@ static int nb_soft_regs;
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
 
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START m68hc11_file_start
+#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO  m68hc11_encode_section_info
+
+#undef TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS m68hc11_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST m68hc11_address_cost
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
+
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_callee_copies_named
+
+#undef TARGET_STRIP_NAME_ENCODING
+#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 int
-m68hc11_override_options ()
+m68hc11_override_options (void)
 {
-  m68hc11_add_gc_roots ();
-
   memset (m68hc11_reg_valid_for_index, 0,
          sizeof (m68hc11_reg_valid_for_index));
   memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
@@ -233,21 +276,20 @@ m68hc11_override_options ()
   /* Compilation with -fpic generates a wrong code.  */
   if (flag_pic)
     {
-      warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
+      warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
               (flag_pic > 1) ? "PIC" : "pic");
       flag_pic = 0;
     }
 
+  /* Do not enable -fweb because it breaks the 32-bit shift patterns
+     by breaking the match_dup of those patterns.  The shift patterns
+     will no longer be recognized after that.  */
+  flag_web = 0;
+
   /* Configure for a 68hc11 processor.  */
   if (TARGET_M6811)
     {
-      /* If gcc was built for a 68hc12, invalidate that because
-         a -m68hc11 option was specified on the command line.  */
-      if (TARGET_DEFAULT != MASK_M6811)
-        target_flags &= ~TARGET_DEFAULT;
-
-      if (!TARGET_M6812)
-        target_flags &= ~TARGET_AUTO_INC_DEC;
+      target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
       m68hc11_cost = &m6811_cost;
       m68hc11_min_offset = 0;
       m68hc11_max_offset = 256;
@@ -258,8 +300,10 @@ m68hc11_override_options ()
       m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
       m68hc11_sp_correction = 1;
       m68hc11_tmp_regs_class = D_REGS;
-      if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
-       m68hc11_soft_reg_count = "4";
+      m68hc11_addr_mode = ADDR_OFFSET;
+      m68hc11_mov_addr_mode = 0;
+      if (m68hc11_soft_reg_count < 0)
+       m68hc11_soft_reg_count = 4;
     }
 
   /* Configure for a 68hc12 processor.  */
@@ -277,43 +321,30 @@ m68hc11_override_options ()
       m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
       m68hc11_sp_correction = 0;
       m68hc11_tmp_regs_class = TMP_REGS;
-      target_flags &= ~MASK_M6811;
+      m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
+        | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
+      m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
+        | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
       target_flags |= MASK_NO_DIRECT_MODE;
-      if (m68hc11_soft_reg_count == 0)
-       m68hc11_soft_reg_count = "0";
-    }
-  return 0;
-}
+      if (m68hc11_soft_reg_count < 0)
+       m68hc11_soft_reg_count = 0;
 
-
-int
-m68hc11_optimization_options (level, size)
-     int level ATTRIBUTE_UNUSED;
-     int size;
-{
-  /* When optimizing for size, do not reorder basic blocks because
-     it duplicates some insns for speed and this results in larder code.
-     This reordering can still be enabled but explicitly.  */
-  if (size)
-    {
-      flag_reorder_blocks = 0;
+      if (TARGET_LONG_CALLS)
+        current_function_far = 1;
     }
   return 0;
 }
 
+
 void
-m68hc11_conditional_register_usage ()
+m68hc11_conditional_register_usage (void)
 {
   int i;
-  int cnt = atoi (m68hc11_soft_reg_count);
 
-  if (cnt < 0)
-    cnt = 0;
-  if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
-    cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
+  if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
+    m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
 
-  nb_soft_regs = cnt;
-  for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
+  for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
     {
       fixed_regs[i] = 1;
       call_used_regs[i] = 1;
@@ -331,48 +362,44 @@ m68hc11_conditional_register_usage ()
 
 /* Reload and register operations.  */
 
-static const char *const reg_class_names[] = REG_CLASS_NAMES;
-
 
 void
-create_regs_rtx ()
+create_regs_rtx (void)
 {
   /*  regs_inited = 1; */
-  ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
-  iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
-  d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
-  da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
-  m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
-
-  stack_push_word = gen_rtx (MEM, HImode,
-                            gen_rtx (PRE_DEC, HImode,
-                                     gen_rtx (REG, HImode, HARD_SP_REGNUM)));
-  stack_pop_word = gen_rtx (MEM, HImode,
-                           gen_rtx (POST_INC, HImode,
-                                    gen_rtx (REG, HImode, HARD_SP_REGNUM)));
+  ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
+  iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
+  d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
+  m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
+
+  stack_push_word = gen_rtx_MEM (HImode,
+                            gen_rtx_PRE_DEC (HImode,
+                                     gen_rtx_REG (HImode, HARD_SP_REGNUM)));
+  stack_pop_word = gen_rtx_MEM (HImode,
+                           gen_rtx_POST_INC (HImode,
+                                    gen_rtx_REG (HImode, HARD_SP_REGNUM)));
 
 }
 
 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
-    - 8 bit values are stored anywhere (except the SP register).
-    - 16 bit values can be stored in any register whose mode is 16
-    - 32 bit values can be stored in D, X registers or in a soft register
+    - 8-bit values are stored anywhere (except the SP register).
+    - 16-bit values can be stored in any register whose mode is 16
+    - 32-bit values can be stored in D, X registers or in a soft register
       (except the last one because we need 2 soft registers)
     - Values whose size is > 32 bit are not stored in real hard
       registers.  They may be stored in soft registers if there are
       enough of them.  */
 int
-hard_regno_mode_ok (regno, mode)
-     int regno;
-     enum machine_mode mode;
+hard_regno_mode_ok (int regno, enum machine_mode mode)
 {
   switch (GET_MODE_SIZE (mode))
     {
     case 8:
-      return S_REGNO_P (regno) && nb_soft_regs >= 4;
+      return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
 
     case 4:
-      return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
+      return (X_REGNO_P (regno)
+             || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
 
     case 2:
       return G_REGNO_P (regno);
@@ -391,10 +418,24 @@ hard_regno_mode_ok (regno, mode)
     }
 }
 
+int
+m68hc11_hard_regno_rename_ok (int reg1, int reg2)
+{
+  /* Don't accept renaming to Z register.  We will replace it to
+     X,Y or D during machine reorg pass.  */
+  if (reg2 == HARD_Z_REGNUM)
+    return 0;
+
+  /* Don't accept renaming D,X to Y register as the code will be bigger.  */
+  if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
+      && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
+    return 0;
+
+  return 1;
+}
+
 enum reg_class
-preferred_reload_class (operand, class)
-     rtx operand;
-     enum reg_class class;
+preferred_reload_class (rtx operand, enum reg_class rclass)
 {
   enum machine_mode mode;
 
@@ -402,97 +443,97 @@ preferred_reload_class (operand, class)
 
   if (debug_m6811)
     {
-      printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
+      printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
     }
 
-  if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
+  if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
     return m68hc11_base_reg_class;
 
-  if (class >= S_REGS && (GET_CODE (operand) == MEM
+  if (rclass >= S_REGS && (GET_CODE (operand) == MEM
                          || GET_CODE (operand) == CONST_INT))
     {
       /* S_REGS class must not be used.  The movhi template does not
          work to move a memory to a soft register.
          Restrict to a hard reg.  */
-      switch (class)
+      switch (rclass)
        {
        default:
        case G_REGS:
        case D_OR_A_OR_S_REGS:
-         class = A_OR_D_REGS;
+         rclass = A_OR_D_REGS;
          break;
        case A_OR_S_REGS:
-         class = A_REGS;
+         rclass = A_REGS;
          break;
        case D_OR_SP_OR_S_REGS:
-         class = D_OR_SP_REGS;
+         rclass = D_OR_SP_REGS;
          break;
        case D_OR_Y_OR_S_REGS:
-         class = D_OR_Y_REGS;
+         rclass = D_OR_Y_REGS;
          break;
        case D_OR_X_OR_S_REGS:
-         class = D_OR_X_REGS;
+         rclass = D_OR_X_REGS;
          break;
        case SP_OR_S_REGS:
-         class = SP_REGS;
+         rclass = SP_REGS;
          break;
        case Y_OR_S_REGS:
-         class = Y_REGS;
+         rclass = Y_REGS;
          break;
        case X_OR_S_REGS:
-         class = X_REGS;
+         rclass = X_REGS;
          break;
        case D_OR_S_REGS:
-         class = D_REGS;
+         rclass = D_REGS;
        }
     }
-  else if (class == Y_REGS && GET_CODE (operand) == MEM)
+  else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
     {
-      class = Y_REGS;
+      rclass = Y_REGS;
     }
-  else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
+  else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
     {
-      class = D_OR_X_REGS;
+      rclass = D_OR_X_REGS;
     }
-  else if (class >= S_REGS && S_REG_P (operand))
+  else if (rclass >= S_REGS && S_REG_P (operand))
     {
-      switch (class)
+      switch (rclass)
        {
        default:
        case G_REGS:
        case D_OR_A_OR_S_REGS:
-         class = A_OR_D_REGS;
+         rclass = A_OR_D_REGS;
          break;
        case A_OR_S_REGS:
-         class = A_REGS;
+         rclass = A_REGS;
          break;
        case D_OR_SP_OR_S_REGS:
-         class = D_OR_SP_REGS;
+         rclass = D_OR_SP_REGS;
          break;
        case D_OR_Y_OR_S_REGS:
-         class = D_OR_Y_REGS;
+         rclass = D_OR_Y_REGS;
          break;
        case D_OR_X_OR_S_REGS:
-         class = D_OR_X_REGS;
+         rclass = D_OR_X_REGS;
          break;
        case SP_OR_S_REGS:
-         class = SP_REGS;
+         rclass = SP_REGS;
          break;
        case Y_OR_S_REGS:
-         class = Y_REGS;
+         rclass = Y_REGS;
          break;
        case X_OR_S_REGS:
-         class = X_REGS;
+         rclass = X_REGS;
          break;
        case D_OR_S_REGS:
-         class = D_REGS;
+         rclass = D_REGS;
        }
     }
-  else if (class >= S_REGS)
+  else if (rclass >= S_REGS)
     {
       if (debug_m6811)
        {
-         printf ("Class = %s for: ", reg_class_names[class]);
+         printf ("Class = %s for: ", reg_class_names[rclass]);
          fflush (stdout);
          debug_rtx (operand);
        }
@@ -500,33 +541,37 @@ preferred_reload_class (operand, class)
 
   if (debug_m6811)
     {
-      printf (" => class=%s\n", reg_class_names[class]);
+      printf (" => class=%s\n", reg_class_names[rclass]);
       fflush (stdout);
       debug_rtx (operand);
     }
 
-  return class;
+  return rclass;
 }
 
 /* Return 1 if the operand is a valid indexed addressing mode.
    For 68hc11:  n,r    with n in [0..255] and r in A_REGS class
    For 68hc12:  n,r    no constraint on the constant, r in A_REGS class.  */
-static int
-register_indirect_p (operand, mode, strict)
-     rtx operand;
-     enum machine_mode mode;
-     int strict;
+int
+m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
 {
   rtx base, offset;
 
   switch (GET_CODE (operand))
     {
+    case MEM:
+      if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
+        return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
+                                   addr_mode & (ADDR_STRICT | ADDR_OFFSET));
+      return 0;
+
     case POST_INC:
     case PRE_INC:
     case POST_DEC:
     case PRE_DEC:
-      if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
-       return register_indirect_p (XEXP (operand, 0), mode, strict);
+      if (addr_mode & ADDR_INCDEC)
+       return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
+                                   addr_mode & ADDR_STRICT);
       return 0;
 
     case PLUS:
@@ -538,36 +583,57 @@ register_indirect_p (operand, mode, strict)
       if (GET_CODE (offset) == MEM)
        return 0;
 
+      /* Indexed addressing mode with 2 registers.  */
+      if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
+        {
+          if (!(addr_mode & ADDR_INDEXED))
+            return 0;
+
+          addr_mode &= ADDR_STRICT;
+          if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
+              && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
+            return 1;
+
+          if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
+              && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
+            return 1;
+
+          return 0;
+        }
+
+      if (!(addr_mode & ADDR_OFFSET))
+        return 0;
+
       if (GET_CODE (base) == REG)
        {
-         if (!VALID_CONSTANT_OFFSET_P (offset, mode))
+          if (!VALID_CONSTANT_OFFSET_P (offset, mode))
            return 0;
 
-         if (strict == 0)
+         if (!(addr_mode & ADDR_STRICT))
            return 1;
 
-         return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
+         return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
        }
+
       if (GET_CODE (offset) == REG)
        {
          if (!VALID_CONSTANT_OFFSET_P (base, mode))
            return 0;
 
-         if (strict == 0)
+         if (!(addr_mode & ADDR_STRICT))
            return 1;
 
-         return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
+         return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
        }
       return 0;
 
     case REG:
-      return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
+      return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
 
     case CONST_INT:
-      if (TARGET_M6811)
-        return 0;
-
-      return VALID_CONSTANT_OFFSET_P (operand, mode);
+      if (addr_mode & ADDR_CONST)
+        return VALID_CONSTANT_OFFSET_P (operand, mode);
+      return 0;
 
     default:
       return 0;
@@ -577,11 +643,10 @@ register_indirect_p (operand, mode, strict)
 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
    a 68HC12 1-byte index addressing mode.  */
 int
-m68hc11_small_indexed_indirect_p (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
+m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
 {
   rtx base, offset;
+  int addr_mode;
 
   if (GET_CODE (operand) == REG && reload_in_progress
       && REGNO (operand) >= FIRST_PSEUDO_REGISTER
@@ -601,7 +666,8 @@ m68hc11_small_indexed_indirect_p (operand, mode)
   if (PUSH_POP_ADDRESS_P (operand))
     return 1;
 
-  if (!register_indirect_p (operand, mode, reload_completed))
+  addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
+  if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
     return 0;
 
   if (TARGET_M6812 && GET_CODE (operand) == PLUS
@@ -640,25 +706,32 @@ m68hc11_small_indexed_indirect_p (operand, mode)
 }
 
 int
-m68hc11_register_indirect_p (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
+m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
 {
+  int addr_mode;
+
+  if (GET_CODE (operand) == REG && reload_in_progress
+      && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+      && reg_equiv_memory_loc[REGNO (operand)])
+    {
+      operand = reg_equiv_memory_loc[REGNO (operand)];
+      operand = eliminate_regs (operand, 0, NULL_RTX);
+    }
   if (GET_CODE (operand) != MEM)
     return 0;
 
   operand = XEXP (operand, 0);
-  return register_indirect_p (operand, mode,
-                              (reload_completed | reload_in_progress));
+  addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
+  return m68hc11_valid_addressing_p (operand, mode, addr_mode);
 }
 
 static int
-go_if_legitimate_address_internal (operand, mode, strict)
-     rtx operand;
-     enum machine_mode mode;
-     int strict;
+go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
+                                   int strict)
 {
-  if (CONSTANT_ADDRESS_P (operand))
+  int addr_mode;
+
+  if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
     {
       /* Reject the global variables if they are too wide.  This forces
          a load of their address in a register and generates smaller code.  */
@@ -667,7 +740,8 @@ go_if_legitimate_address_internal (operand, mode, strict)
 
       return 1;
     }
-  if (register_indirect_p (operand, mode, strict))
+  addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
+  if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
     {
       return 1;
     }
@@ -683,10 +757,8 @@ go_if_legitimate_address_internal (operand, mode, strict)
 }
 
 int
-m68hc11_go_if_legitimate_address (operand, mode, strict)
-     rtx operand;
-     enum machine_mode mode;
-     int strict;
+m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
+                                  int strict)
 {
   int result;
 
@@ -718,18 +790,16 @@ m68hc11_go_if_legitimate_address (operand, mode, strict)
 }
 
 int
-m68hc11_legitimize_address (operand, old_operand, mode)
-     rtx *operand ATTRIBUTE_UNUSED;
-     rtx old_operand ATTRIBUTE_UNUSED;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
+                            rtx old_operand ATTRIBUTE_UNUSED,
+                            enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 
 int
-m68hc11_reload_operands (operands)
-     rtx operands[];
+m68hc11_reload_operands (rtx operands[])
 {
   enum machine_mode mode;
 
@@ -752,9 +822,9 @@ m68hc11_reload_operands (operands)
        }
 
       /* If the offset is out of range, we have to compute the address
-         with a separate add instruction.  We try to do with with an 8-bit
+         with a separate add instruction.  We try to do this with an 8-bit
          add on the A register.  This is possible only if the lowest part
-         of the offset (ie, big_offset % 256) is a valid constant offset
+         of the offset (i.e., big_offset % 256) is a valid constant offset
          with respect to the mode.  If it's not, we have to generate a
          16-bit add on the D register.  From:
        
@@ -802,19 +872,19 @@ m68hc11_reload_operands (operands)
          offset = GEN_INT (vl);
          if (!VALID_CONSTANT_OFFSET_P (offset, mode))
            {
-             emit_insn (gen_rtx (SET, VOIDmode, reg,
-                                 gen_rtx (PLUS, HImode, reg, big_offset)));
+             emit_insn (gen_rtx_SET (VOIDmode, reg,
+                                 gen_rtx_PLUS (HImode, reg, big_offset)));
              offset = const0_rtx;
            }
          else
            {
-             emit_insn (gen_rtx (SET, VOIDmode, reg,
-                                 gen_rtx (PLUS, HImode, reg,
+             emit_insn (gen_rtx_SET (VOIDmode, reg,
+                                 gen_rtx_PLUS (HImode, reg,
                                           GEN_INT (vh << 8))));
            }
          emit_move_insn (operands[0],
-                         gen_rtx (MEM, GET_MODE (operands[1]),
-                                  gen_rtx (PLUS, Pmode, reg, offset)));
+                         gen_rtx_MEM (GET_MODE (operands[1]),
+                                  gen_rtx_PLUS (Pmode, reg, offset)));
          return 1;
        }
     }
@@ -824,13 +894,9 @@ m68hc11_reload_operands (operands)
 }
 
 void
-m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
-     const char *name;
-     enum rtx_code code;
-     enum machine_mode dmode;
-     enum machine_mode smode;
-     int noperands;
-     rtx *operands;
+m68hc11_emit_libcall (const char *name, enum rtx_code code,
+                      enum machine_mode dmode, enum machine_mode smode,
+                      int noperands, rtx *operands)
 {
   rtx ret;
   rtx insns;
@@ -844,7 +910,7 @@ m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
     case 2:
       ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
                                      dmode, 1, operands[1], smode);
-      equiv = gen_rtx (code, dmode, operands[1]);
+      equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
       break;
 
     case 3:
@@ -852,11 +918,11 @@ m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
                                      LCT_CONST, dmode, 2,
                                      operands[1], smode, operands[2],
                                      smode);
-      equiv = gen_rtx (code, dmode, operands[1], operands[2]);
+      equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   insns = get_insns ();
@@ -867,9 +933,8 @@ m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
 /* Returns true if X is a PRE/POST increment decrement
    (same as auto_inc_p() in rtlanal.c but do not take into
    account the stack).  */
-static int
-m68hc11_auto_inc_p (x)
-     rtx x;
+int
+m68hc11_auto_inc_p (rtx x)
 {
   return GET_CODE (x) == PRE_DEC
     || GET_CODE (x) == POST_INC
@@ -880,9 +945,7 @@ m68hc11_auto_inc_p (x)
 /* Predicates for machine description.  */
 
 int
-memory_reload_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return GET_CODE (operand) == MEM
     && GET_CODE (XEXP (operand, 0)) == PLUS
@@ -893,74 +956,7 @@ memory_reload_operand (operand, mode)
 }
 
 int
-tst_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
-{
-  if (GET_CODE (operand) == MEM && reload_completed == 0)
-    {
-      rtx addr = XEXP (operand, 0);
-      if (m68hc11_auto_inc_p (addr))
-       return 0;
-    }
-  return nonimmediate_operand (operand, mode);
-}
-
-int
-cmp_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
-{
-  if (GET_CODE (operand) == MEM)
-    {
-      rtx addr = XEXP (operand, 0);
-      if (m68hc11_auto_inc_p (addr))
-       return 0;
-    }
-  return general_operand (operand, mode);
-}
-
-int
-non_push_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
-{
-  if (general_operand (operand, mode) == 0)
-    return 0;
-
-  if (push_operand (operand, mode) == 1)
-    return 0;
-  return 1;
-}
-
-int
-reg_or_some_mem_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
-{
-  if (GET_CODE (operand) == MEM)
-    {
-      rtx op = XEXP (operand, 0);
-
-      if (symbolic_memory_operand (op, mode))
-       return 1;
-
-      if (IS_STACK_PUSH (operand))
-       return 1;
-
-      if (m68hc11_register_indirect_p (operand, mode))
-       return 1;
-
-      return 0;
-    }
-
-  return register_operand (operand, mode);
-}
-
-int
-m68hc11_symbolic_p (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
+m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
 {
   if (GET_CODE (operand) == MEM)
     {
@@ -973,79 +969,31 @@ m68hc11_symbolic_p (operand, mode)
 }
 
 int
-m68hc11_indirect_p (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
+m68hc11_indirect_p (rtx operand, enum machine_mode mode)
 {
-  if (GET_CODE (operand) == MEM)
+  if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
     {
       rtx op = XEXP (operand, 0);
+      int addr_mode;
+
+      if (m68hc11_page0_symbol_p (op))
+        return 1;
 
       if (symbolic_memory_operand (op, mode))
-       return 0;
+       return TARGET_M6812;
 
       if (reload_in_progress)
         return 1;
 
       operand = XEXP (operand, 0);
-      return register_indirect_p (operand, mode, reload_completed);
+      addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
+      return m68hc11_valid_addressing_p (operand, mode, addr_mode);
     }
   return 0;
 }
 
 int
-stack_register_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return SP_REG_P (operand);
-}
-
-int
-d_register_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (operand) == SUBREG)
-    operand = XEXP (operand, 0);
-
-  return GET_CODE (operand) == REG
-    && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
-       || REGNO (operand) == HARD_D_REGNUM
-        || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
-}
-
-int
-hard_addr_reg_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (operand) == SUBREG)
-    operand = XEXP (operand, 0);
-
-  return GET_CODE (operand) == REG
-    && (REGNO (operand) == HARD_X_REGNUM
-       || REGNO (operand) == HARD_Y_REGNUM
-       || REGNO (operand) == HARD_Z_REGNUM);
-}
-
-int
-hard_reg_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (operand) == SUBREG)
-    operand = XEXP (operand, 0);
-
-  return GET_CODE (operand) == REG
-    && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
-       || H_REGNO_P (REGNO (operand)));
-}
-
-int
-memory_indexed_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (operand) != MEM)
     return 0;
@@ -1064,8 +1012,7 @@ memory_indexed_operand (operand, mode)
 }
 
 int
-push_pop_operand_p (operand)
-     rtx operand;
+push_pop_operand_p (rtx operand)
 {
   if (GET_CODE (operand) != MEM)
     {
@@ -1079,9 +1026,7 @@ push_pop_operand_p (operand)
    reference and a constant.  */
 
 int
-symbolic_memory_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+symbolic_memory_operand (rtx op, enum machine_mode mode)
 {
   switch (GET_CODE (op))
     {
@@ -1107,45 +1052,6 @@ symbolic_memory_operand (op, mode)
       return 0;
     }
 }
-
-int
-m68hc11_logical_operator (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
-}
-
-int
-m68hc11_arith_operator (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
-    || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
-    || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
-    || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
-    || GET_CODE (op) == ROTATERT;
-}
-
-int
-m68hc11_non_shift_operator (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
-    || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
-}
-
-
-int
-m68hc11_unary_operator (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == NEG || GET_CODE (op) == NOT
-    || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
-}
 \f
 /* Emit the code to build the trampoline used to call a nested function.
    
@@ -1157,10 +1063,7 @@ m68hc11_unary_operator (op, mode)
 
 */
 void
-m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp;
-     rtx fnaddr;
-     rtx cxt;
+m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 {
   const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
 
@@ -1197,89 +1100,195 @@ m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
 \f
 /* Declaration of types.  */
 
+/* Handle an "tiny_data" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+m68hc11_handle_page0_attribute (tree *node, tree name,
+                                tree args ATTRIBUTE_UNUSED,
+                                int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+    {
+      DECL_SECTION_NAME (decl) = build_string (6, ".page0");
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qs attribute ignored",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 const struct attribute_spec m68hc11_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
   { "interrupt", 0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
   { "trap",      0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
+  { "far",       0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
+  { "near",      0, 0, false, true,  true,  m68hc11_handle_fntype_attribute },
+  { "page0",     0, 0, false, false, false, m68hc11_handle_page0_attribute },
   { NULL,        0, 0, false, false, false, NULL }
 };
 
+/* Keep track of the symbol which has a `trap' attribute and which uses
+   the `swi' calling convention.  Since there is only one trap, we only
+   record one such symbol.  If there are several, a warning is reported.  */
+static rtx trap_handler_symbol = 0;
+
 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
    arguments as in struct attribute_spec.handler.  */
 static tree
-m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
-     tree name;
-     tree args ATTRIBUTE_UNUSED;
-     int flags ATTRIBUTE_UNUSED;
-     bool *no_add_attrs;
+m68hc11_handle_fntype_attribute (tree *node, tree name,
+                                 tree args ATTRIBUTE_UNUSED,
+                                 int flags ATTRIBUTE_UNUSED,
+                                 bool *no_add_attrs)
 {
   if (TREE_CODE (*node) != FUNCTION_TYPE
+      && TREE_CODE (*node) != METHOD_TYPE
       && TREE_CODE (*node) != FIELD_DECL
       && TREE_CODE (*node) != TYPE_DECL)
     {
-      warning ("`%s' attribute only applies to functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
 
   return NULL_TREE;
 }
+/* Undo the effects of the above.  */
 
-/* Define this macro if references to a symbol must be treated
-   differently depending on something about the variable or function
-   named by the symbol (such as what section it is in).
+static const char *
+m68hc11_strip_name_encoding (const char *str)
+{
+  return str + (*str == '*' || *str == '@' || *str == '&');
+}
 
-   For the 68HC11, we want to recognize trap handlers so that we
-   handle calls to traps in a special manner (by issuing the trap).
-   This information is stored in SYMBOL_REF_FLAG.  */
-void
-m68hc11_encode_section_info (decl)
-     tree decl;
+static void
+m68hc11_encode_label (tree decl)
+{
+  const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  int len = strlen (str);
+  char *newstr = XALLOCAVEC (char, len + 2);
+
+  newstr[0] = '@';
+  strcpy (&newstr[1], str);
+
+  XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
+}
+
+/* Return 1 if this is a symbol in page0  */
+int
+m68hc11_page0_symbol_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+      return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
+
+    case CONST:
+      return m68hc11_page0_symbol_p (XEXP (x, 0));
+
+    case PLUS:
+      if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
+        return 0;
+
+      return GET_CODE (XEXP (x, 1)) == CONST_INT
+        && INTVAL (XEXP (x, 1)) < 256
+        && INTVAL (XEXP (x, 1)) >= 0;
+
+    default:
+      return 0;
+    }
+}
+
+/* We want to recognize trap handlers so that we handle calls to traps
+   in a special manner (by issuing the trap).  This information is stored
+   in SYMBOL_REF_FLAG.  */
+
+static void
+m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
 {
   tree func_attr;
   int trap_handler;
-  rtx rtl;
+  int is_far = 0;
+  
+  if (TREE_CODE (decl) == VAR_DECL)
+    {
+      if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
+        m68hc11_encode_label (decl);
+      return;
+    }
 
   if (TREE_CODE (decl) != FUNCTION_DECL)
     return;
 
-  rtl = DECL_RTL (decl);
-
   func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
+
+
+  if (lookup_attribute ("far", func_attr) != NULL_TREE)
+    is_far = 1;
+  else if (lookup_attribute ("near", func_attr) == NULL_TREE)
+    is_far = TARGET_LONG_CALLS != 0;
+
   trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
-  SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
+  if (trap_handler && is_far)
+    {
+      warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
+              "not compatible, ignoring %<far%>");
+      trap_handler = 0;
+    }
+  if (trap_handler)
+    {
+      if (trap_handler_symbol != 0)
+        warning (OPT_Wattributes, "%<trap%> attribute is already used");
+      else
+        trap_handler_symbol = XEXP (rtl, 0);
+    }
+  SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
 }
-\f
 
-/* Argument support functions.  */
+static unsigned int
+m68hc11_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+  if (strncmp (name, ".eeprom", 7) == 0)
+    {
+      flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
+    }
+
+  return flags;
+}
+
+int
+m68hc11_is_far_symbol (rtx sym)
+{
+  if (GET_CODE (sym) == MEM)
+    sym = XEXP (sym, 0);
 
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
-   Arrays are passed by references and other types by value.
+  return SYMBOL_REF_FLAG (sym);
+}
 
-   SCz: I tried to pass DImode by reference but it seems that this
-   does not work very well.  */
 int
-m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
-     const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+m68hc11_is_trap_symbol (rtx sym)
 {
-  return ((type && TREE_CODE (type) == ARRAY_TYPE)
-         /* Consider complex values as aggregates, so care for TCmode.  */
-         /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
-         /*|| (type && AGGREGATE_TYPE_P (type))) */ );
+  if (GET_CODE (sym) == MEM)
+    sym = XEXP (sym, 0);
+
+  return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
 }
+\f
 
+/* Argument support functions.  */
 
 /* Define the offset between two registers, one to be eliminated, and the
    other its replacement, at the start of a routine.  */
 int
-m68hc11_initial_elimination_offset (from, to)
-     int from;
-     int to;
+m68hc11_initial_elimination_offset (int from, int to)
 {
   int trap_handler;
   tree func_attr;
@@ -1289,9 +1298,26 @@ m68hc11_initial_elimination_offset (from, to)
   /* For a trap handler, we must take into account the registers which
      are pushed on the stack during the trap (except the PC).  */
   func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
+  current_function_interrupt = lookup_attribute ("interrupt",
+                                                func_attr) != NULL_TREE;
   trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
+
+  if (lookup_attribute ("far", func_attr) != 0)
+    current_function_far = 1;
+  else if (lookup_attribute ("near", func_attr) != 0)
+    current_function_far = 0;
+  else
+    current_function_far = (TARGET_LONG_CALLS != 0
+                            && !current_function_interrupt
+                            && !trap_handler);
+
   if (trap_handler && from == ARG_POINTER_REGNUM)
     size = 7;
+
+  /* For a function using 'call/rtc' we must take into account the
+     page register which is pushed in the call.  */
+  else if (current_function_far && from == ARG_POINTER_REGNUM)
+    size = 1;
   else
     size = 0;
 
@@ -1310,7 +1336,7 @@ m68hc11_initial_elimination_offset (from, to)
   /* Push any 2 byte pseudo hard registers that we need to save.  */
   for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
     {
-      if (regs_ever_live[regno] && !call_used_regs[regno])
+      if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
        {
          size += 2;
        }
@@ -1333,10 +1359,7 @@ m68hc11_initial_elimination_offset (from, to)
    For a library call, FNTYPE is 0.  */
 
 void
-m68hc11_init_cumulative_args (cum, fntype, libname)
-     CUMULATIVE_ARGS *cum;
-     tree fntype;
-     rtx libname;
+m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
 {
   tree ret_type;
 
@@ -1377,7 +1400,7 @@ m68hc11_init_cumulative_args (cum, fntype, libname)
 
   ret_type = TREE_TYPE (fntype);
 
-  if (ret_type && aggregate_value_p (ret_type))
+  if (ret_type && aggregate_value_p (ret_type, fntype))
     {
       cum->words = 1;
       cum->nregs = 1;
@@ -1389,11 +1412,8 @@ m68hc11_init_cumulative_args (cum, fntype, libname)
    (TYPE is null for libcalls where that information may not be available.)  */
 
 void
-m68hc11_function_arg_advance (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                              tree type, int named ATTRIBUTE_UNUSED)
 {
   if (mode != BLKmode)
     {
@@ -1430,11 +1450,8 @@ m68hc11_function_arg_advance (cum, mode, type, named)
     (otherwise it is an extra parameter matching an ellipsis).  */
 
 struct rtx_def *
-m68hc11_function_arg (cum, mode, type, named)
-     const CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type ATTRIBUTE_UNUSED;
-     int named ATTRIBUTE_UNUSED;
+m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                      tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
 {
   if (cum->words != 0)
     {
@@ -1444,85 +1461,17 @@ m68hc11_function_arg (cum, mode, type, named)
   if (mode != BLKmode)
     {
       if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
-       return gen_rtx (REG, mode, HARD_X_REGNUM);
+       return gen_rtx_REG (mode, HARD_X_REGNUM);
 
       if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
        {
          return NULL_RTX;
        }
-      return gen_rtx (REG, mode, HARD_D_REGNUM);
+      return gen_rtx_REG (mode, HARD_D_REGNUM);
     }
   return NULL_RTX;
 }
 
-/* The "standard" implementation of va_start: just assign `nextarg' to
-   the variable.  */
-void
-m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p ATTRIBUTE_UNUSED;
-     tree valist;
-     rtx nextarg;
-{
-  tree t;
-
-  /* SCz: the default implementation in builtins.c adjust the
-     nextarg using UNITS_PER_WORD.  This works only with -mshort
-     and fails when integers are 32-bit.  Here is the correct way.  */
-  if (!stdarg_p)
-    nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
-
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            make_tree (ptr_type_node, nextarg));
-  TREE_SIDE_EFFECTS (t) = 1;
-
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-}
-
-rtx
-m68hc11_va_arg (valist, type)
-     tree valist;
-     tree type;
-{
-  tree addr_tree, t;
-  HOST_WIDE_INT align;
-  HOST_WIDE_INT rounded_size;
-  rtx addr;
-  int pad_direction;
-
-  /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
-
-  /* Get AP.  */
-  addr_tree = valist;
-  pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
-
-  if (pad_direction == downward)
-    {
-      /* Small args are padded downward.  */
-
-      HOST_WIDE_INT adj;
-      adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
-      if (rounded_size > align)
-       adj = rounded_size;
-
-      addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-                        build_int_2 (rounded_size - adj, 0));
-    }
-
-  addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
-  addr = copy_to_reg (addr);
-
-  /* Compute new value for AP.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                   build_int_2 (rounded_size, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-  return addr;
-}
-
 /* If defined, a C expression which determines whether, and in which direction,
    to pad out an argument with extra space.  The value should be of type
    `enum direction': either `upward' to pad above the argument,
@@ -1530,21 +1479,13 @@ m68hc11_va_arg (valist, type)
 
    Structures are stored left shifted in their argument slot.  */
 int
-m68hc11_function_arg_padding (mode, type)
-     enum machine_mode mode;
-     tree type;
+m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
 {
   if (type != 0 && AGGREGATE_TYPE_P (type))
     return upward;
 
-  /* This is the default definition.  */
-  return (!BYTES_BIG_ENDIAN
-         ? upward
-         : ((mode == BLKmode
-             ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
-                && int_size_in_bytes (type) <
-                (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
-             PARM_BOUNDARY) ? downward : upward));
+  /* Fall back to the default.  */
+  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
 }
 \f
 
@@ -1553,8 +1494,7 @@ m68hc11_function_arg_padding (mode, type)
 /* Emit a move after the reload pass has completed.  This is used to
    emit the prologue and epilogue.  */
 static void
-emit_move_after_reload (to, from, scratch)
-     rtx to, from, scratch;
+emit_move_after_reload (rtx to, rtx from, rtx scratch)
 {
   rtx insn;
 
@@ -1596,7 +1536,7 @@ emit_move_after_reload (to, from, scratch)
 }
 
 int
-m68hc11_total_frame_size ()
+m68hc11_total_frame_size (void)
 {
   int size;
   int regno;
@@ -1610,16 +1550,15 @@ m68hc11_total_frame_size ()
     size += HARD_REG_SIZE;
 
   for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
-    if (regs_ever_live[regno] && !call_used_regs[regno])
+    if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
       size += HARD_REG_SIZE;
 
   return size;
 }
 
 static void
-m68hc11_output_function_epilogue (out, size)
-     FILE *out ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
+                                  HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
   /* We catch the function epilogue generation to have a chance
      to clear the z_replacement_completed flag.  */
@@ -1627,15 +1566,14 @@ m68hc11_output_function_epilogue (out, size)
 }
 
 void
-expand_prologue ()
+expand_prologue (void)
 {
   tree func_attr;
   int size;
   int regno;
   rtx scratch;
 
-  if (reload_completed != 1)
-    abort ();
+  gcc_assert (reload_completed == 1);
 
   size = get_frame_size ();
 
@@ -1646,16 +1584,28 @@ expand_prologue ()
   current_function_interrupt = lookup_attribute ("interrupt",
                                                 func_attr) != NULL_TREE;
   current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
+  if (lookup_attribute ("far", func_attr) != NULL_TREE)
+    current_function_far = 1;
+  else if (lookup_attribute ("near", func_attr) != NULL_TREE)
+    current_function_far = 0;
+  else
+    current_function_far = (TARGET_LONG_CALLS != 0
+                            && !current_function_interrupt
+                            && !current_function_trap);
 
   /* Get the scratch register to build the frame and push registers.
      If the first argument is a 32-bit quantity, the D+X registers
      are used.  Use Y to compute the frame.  Otherwise, X is cheaper.
      For 68HC12, this scratch register is not used.  */
-  if (current_function_args_info.nregs == 2)
+  if (crtl->args.info.nregs == 2)
     scratch = iy_reg;
   else
     scratch = ix_reg;
 
+  /* Save current stack frame.  */
+  if (frame_pointer_needed)
+    emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
+
   /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
      Other soft registers in page0 need not to be saved because they
      will be restored by C functions.  For a trap handler, we don't
@@ -1664,23 +1614,19 @@ expand_prologue ()
     {
       emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
       emit_move_after_reload (stack_push_word,
-                             gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
+                             gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
       emit_move_after_reload (stack_push_word,
-                             gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
+                             gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
                              scratch);
     }
 
-  /* Save current stack frame.  */
-  if (frame_pointer_needed)
-    emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
-
   /* Allocate local variables.  */
   if (TARGET_M6812 && (size > 4 || size == 3))
     {
       emit_insn (gen_addhi3 (stack_pointer_rtx,
                             stack_pointer_rtx, GEN_INT (-size)));
     }
-  else if (size > 8)
+  else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
     {
       rtx insn;
 
@@ -1705,7 +1651,7 @@ expand_prologue ()
 
       if (size & 1)
        emit_insn (gen_addhi3 (stack_pointer_rtx,
-                              stack_pointer_rtx, GEN_INT (-1)));
+                              stack_pointer_rtx, constm1_rtx));
     }
 
   /* Create the frame pointer.  */
@@ -1716,38 +1662,37 @@ expand_prologue ()
   /* Push any 2 byte pseudo hard registers that we need to save.  */
   for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
     {
-      if (regs_ever_live[regno] && !call_used_regs[regno])
+      if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
        {
          emit_move_after_reload (stack_push_word,
-                                 gen_rtx (REG, HImode, regno), scratch);
+                                 gen_rtx_REG (HImode, regno), scratch);
        }
     }
 }
 
 void
-expand_epilogue ()
+expand_epilogue (void)
 {
   int size;
   register int regno;
   int return_size;
   rtx scratch;
 
-  if (reload_completed != 1)
-    abort ();
+  gcc_assert (reload_completed == 1);
 
   size = get_frame_size ();
 
   /* If we are returning a value in two registers, we have to preserve the
      X register and use the Y register to restore the stack and the saved
      registers.  Otherwise, use X because it's faster (and smaller).  */
-  if (current_function_return_rtx == 0)
+  if (crtl->return_rtx == 0)
     return_size = 0;
-  else if (GET_CODE (current_function_return_rtx) == MEM)
+  else if (GET_CODE (crtl->return_rtx) == MEM)
     return_size = HARD_REG_SIZE;
   else
-    return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
+    return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
 
-  if (return_size > HARD_REG_SIZE)
+  if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
     scratch = iy_reg;
   else
     scratch = ix_reg;
@@ -1755,9 +1700,9 @@ expand_epilogue ()
   /* Pop any 2 byte pseudo hard registers that we saved.  */
   for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
     {
-      if (regs_ever_live[regno] && !call_used_regs[regno])
+      if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
        {
-         emit_move_after_reload (gen_rtx (REG, HImode, regno),
+         emit_move_after_reload (gen_rtx_REG (HImode, regno),
                                  stack_pop_word, scratch);
        }
     }
@@ -1768,7 +1713,7 @@ expand_epilogue ()
       emit_insn (gen_addhi3 (stack_pointer_rtx,
                             stack_pointer_rtx, GEN_INT (size)));
     }
-  else if (size > 8)
+  else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
     {
       rtx insn;
 
@@ -1791,23 +1736,23 @@ expand_epilogue ()
        emit_move_after_reload (scratch, stack_pop_word, scratch);
       if (size & 1)
        emit_insn (gen_addhi3 (stack_pointer_rtx,
-                              stack_pointer_rtx, GEN_INT (1)));
+                              stack_pointer_rtx, const1_rtx));
     }
 
-  /* Restore previous frame pointer.  */
-  if (frame_pointer_needed)
-    emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
-
   /* For an interrupt handler, restore ZTMP, ZREG and XYREG.  */
   if (current_function_interrupt)
     {
-      emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
+      emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
                              stack_pop_word, scratch);
-      emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
+      emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
                              stack_pop_word, scratch);
       emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
     }
 
+  /* Restore previous frame pointer.  */
+  if (frame_pointer_needed)
+    emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
+
   /* If the trap handler returns some value, copy the value
      in D, X onto the stack so that the rti will pop the return value
      correctly.  */
@@ -1820,12 +1765,12 @@ expand_epilogue ()
          emit_move_after_reload (scratch, stack_pointer_rtx, 0);
          addr_reg = scratch;
        }
-      emit_move_after_reload (gen_rtx (MEM, HImode,
-                                      gen_rtx (PLUS, HImode, addr_reg,
-                                               GEN_INT (1))), d_reg, 0);
+      emit_move_after_reload (gen_rtx_MEM (HImode,
+                                      gen_rtx_PLUS (HImode, addr_reg,
+                                               const1_rtx)), d_reg, 0);
       if (return_size > HARD_REG_SIZE)
-       emit_move_after_reload (gen_rtx (MEM, HImode,
-                                        gen_rtx (PLUS, HImode, addr_reg,
+       emit_move_after_reload (gen_rtx_MEM (HImode,
+                                        gen_rtx_PLUS (HImode, addr_reg,
                                                  GEN_INT (3))), ix_reg, 0);
     }
 
@@ -1838,16 +1783,14 @@ expand_epilogue ()
    fixed to work for constants and 68HC11 specific registers.  */
 
 rtx
-m68hc11_gen_lowpart (mode, x)
-     enum machine_mode mode;
-     rtx x;
+m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
 {
   /* We assume that the low part of an auto-inc mode is the same with
      the mode changed and that the caller split the larger mode in the
      correct order.  */
   if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
     {
-      return gen_rtx (MEM, mode, XEXP (x, 0));
+      return gen_rtx_MEM (mode, XEXP (x, 0));
     }
 
   /* Note that a CONST_DOUBLE rtx could represent either an integer or a
@@ -1877,32 +1820,39 @@ m68hc11_gen_lowpart (mode, x)
          if (mode == SImode)
            return GEN_INT (l[0]);
 
-         return GEN_INT (trunc_int_for_mode (l[0], HImode));
+         return gen_int_mode (l[0], HImode);
        }
       else
        {
          l[0] = CONST_DOUBLE_LOW (x);
        }
-      if (mode == SImode)
-       return GEN_INT (l[0]);
-      else if (mode == HImode && GET_MODE (x) == SFmode)
-       return GEN_INT (trunc_int_for_mode (l[0], HImode));
-      else
-       abort ();
+      switch (mode)
+       {
+       case SImode:
+         return GEN_INT (l[0]);
+       case HImode:
+         gcc_assert (GET_MODE (x) == SFmode);
+         return gen_int_mode (l[0], HImode);
+       default:
+         gcc_unreachable ();
+       }
     }
 
   if (mode == QImode && D_REG_P (x))
-    return gen_rtx (REG, mode, HARD_B_REGNUM);
+    return gen_rtx_REG (mode, HARD_B_REGNUM);
 
   /* gen_lowpart crashes when it is called with a SUBREG.  */
   if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
     {
-      if (mode == SImode)
-       return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
-      else if (mode == HImode)
-       return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
-      else
-       abort ();
+      switch (mode)
+       {
+       case SImode:
+         return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
+       case HImode:
+         return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
+       default:
+         gcc_unreachable ();
+       }
     }
   x = gen_lowpart (mode, x);
 
@@ -1915,16 +1865,14 @@ m68hc11_gen_lowpart (mode, x)
 }
 
 rtx
-m68hc11_gen_highpart (mode, x)
-     enum machine_mode mode;
-     rtx x;
+m68hc11_gen_highpart (enum machine_mode mode, rtx x)
 {
   /* We assume that the high part of an auto-inc mode is the same with
      the mode changed and that the caller split the larger mode in the
      correct order.  */
   if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
     {
-      return gen_rtx (MEM, mode, XEXP (x, 0));
+      return gen_rtx_MEM (mode, XEXP (x, 0));
     }
 
   /* Note that a CONST_DOUBLE rtx could represent either an integer or a
@@ -1954,19 +1902,23 @@ m68hc11_gen_highpart (mode, x)
          if (mode == SImode)
            return GEN_INT (l[1]);
 
-         return GEN_INT (trunc_int_for_mode ((l[1] >> 16), HImode));
+         return gen_int_mode ((l[1] >> 16), HImode);
        }
       else
        {
          l[1] = CONST_DOUBLE_HIGH (x);
        }
 
-      if (mode == SImode)
-       return GEN_INT (l[1]);
-      else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
-       return GEN_INT (trunc_int_for_mode ((l[0] >> 16), HImode));
-      else
-       abort ();
+      switch (mode)
+       {
+       case SImode:
+         return GEN_INT (l[1]);
+       case HImode:
+         gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
+         return gen_int_mode ((l[0] >> 16), HImode);
+       default:
+         gcc_unreachable ();
+       }
     }
   if (GET_CODE (x) == CONST_INT)
     {
@@ -1974,15 +1926,19 @@ m68hc11_gen_highpart (mode, x)
 
       if (mode == QImode)
        {
-         return GEN_INT (trunc_int_for_mode (val >> 8, QImode));
+         return gen_int_mode (val >> 8, QImode);
        }
       else if (mode == HImode)
        {
-         return GEN_INT (trunc_int_for_mode (val >> 16, HImode));
+         return gen_int_mode (val >> 16, HImode);
        }
+      else if (mode == SImode)
+       {
+         return gen_int_mode (val >> 32, SImode);
+       }
     }
   if (mode == QImode && D_REG_P (x))
-    return gen_rtx (REG, mode, HARD_A_REGNUM);
+    return gen_rtx_REG (mode, HARD_A_REGNUM);
 
   /* There is no way in GCC to represent the upper part of a word register.
      To obtain the 8-bit upper part of a soft register, we change the
@@ -1995,26 +1951,22 @@ m68hc11_gen_highpart (mode, x)
       /* Avoid the '*' for direct addressing mode when this
          addressing mode is disabled.  */
       pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
-      return gen_rtx (MEM, QImode,
-                     gen_rtx (SYMBOL_REF, Pmode,
+      return gen_rtx_MEM (QImode,
+                     gen_rtx_SYMBOL_REF (Pmode,
                               &reg_names[REGNO (x)][pos]));
     }
 
   /* gen_highpart crashes when it is called with a SUBREG.  */
-  if (GET_CODE (x) == SUBREG)
-    {
-      return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
-    }
-  if (GET_CODE (x) == REG)
+  switch (GET_CODE (x))
     {
+    case SUBREG:
+      return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
+    case REG:
       if (REGNO (x) < FIRST_PSEUDO_REGISTER)
-        return gen_rtx (REG, mode, REGNO (x));
+        return gen_rtx_REG (mode, REGNO (x));
       else
         return gen_rtx_SUBREG (mode, x, 0);
-    }
-
-  if (GET_CODE (x) == MEM)
-    {
+    case MEM:
       x = change_address (x, mode, 0);
 
       /* Return a different rtx to avoid to share it in several insns
@@ -2023,8 +1975,10 @@ m68hc11_gen_highpart (mode, x)
       if (GET_CODE (x) == MEM)
        x = copy_rtx (x);
       return x;
+
+    default:
+      gcc_unreachable ();
     }
-  abort ();
 }
 \f
 
@@ -2036,20 +1990,18 @@ m68hc11_gen_highpart (mode, x)
    of code when we know that some register dies or can be clobbered.  */
 
 int
-dead_register_here (x, reg)
-     rtx x;
-     rtx reg;
+dead_register_here (rtx x, rtx reg)
 {
   rtx x_reg;
   rtx p;
 
   if (D_REG_P (reg))
-    x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
+    x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
   else
     x_reg = 0;
 
   for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
-    if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+    if (INSN_P (p))
       {
        rtx body;
 
@@ -2116,16 +2068,14 @@ dead_register_here (x, reg)
 
 /* Print the name of register 'regno' in the assembly file.  */
 static void
-asm_print_register (file, regno)
-     FILE *file;
-     int regno;
+asm_print_register (FILE *file, int regno)
 {
   const char *name = reg_names[regno];
 
   if (TARGET_NO_DIRECT_MODE && name[0] == '*')
     name++;
 
-  asm_fprintf (file, "%s", name);
+  fprintf (file, "%s", name);
 }
 
 /* A C compound statement to output to stdio stream STREAM the
@@ -2161,10 +2111,7 @@ asm_print_register (file, regno)
        ignored.  */
 
 void
-print_operand (file, op, letter)
-     FILE *file;
-     rtx op;
-     int letter;
+print_operand (FILE *file, rtx op, int letter)
 {
   if (letter == 't')
     {
@@ -2174,12 +2121,12 @@ print_operand (file, op, letter)
   else if (letter == 'T')
     {
       asm_print_register (file, SOFT_TMP_REGNUM);
-      asm_fprintf (file, "+1");
+      fprintf (file, "+1");
       return;
     }
   else if (letter == '#')
     {
-      asm_fprintf (file, "%0I");
+      asm_fprintf (file, "%I");
     }
 
   if (GET_CODE (op) == REG)
@@ -2187,7 +2134,11 @@ print_operand (file, op, letter)
       if (letter == 'b' && S_REG_P (op))
        {
          asm_print_register (file, REGNO (op));
-         asm_fprintf (file, "+1");
+         fprintf (file, "+1");
+       }
+      else if (letter == 'b' && D_REG_P (op))
+       {
+         asm_print_register (file, HARD_B_REGNUM);
        }
       else
        {
@@ -2199,12 +2150,12 @@ print_operand (file, op, letter)
   if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
     {
       if (letter == 'b')
-       asm_fprintf (file, "%0I%%lo(");
+       asm_fprintf (file, "%I%%lo(");
       else
-       asm_fprintf (file, "%0I%%hi(");
+       asm_fprintf (file, "%I%%hi(");
 
       output_addr_const (file, op);
-      asm_fprintf (file, ")");
+      fprintf (file, ")");
       return;
     }
 
@@ -2228,48 +2179,42 @@ print_operand (file, op, letter)
       switch (GET_CODE (base))
        {
        case PRE_DEC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
          break;
 
        case POST_DEC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             asm_fprintf (file, "-");
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
+         fprintf (file, "-");
          break;
 
        case POST_INC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             asm_fprintf (file, "+");
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
+         fprintf (file, "+");
          break;
 
        case PRE_INC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
          break;
 
+        case MEM:
+          gcc_assert (TARGET_M6812);
+         fprintf (file, "[");
+         print_operand_address (file, XEXP (base, 0));
+         fprintf (file, "]");
+          break;
+
        default:
+          if (m68hc11_page0_symbol_p (base))
+            fprintf (file, "*");
+
          output_address (base);
          break;
        }
@@ -2283,14 +2228,12 @@ print_operand (file, op, letter)
       REAL_VALUE_TO_TARGET_SINGLE (r, l);
       asm_fprintf (file, "%I0x%lx", l);
     }
-  else if (GET_CODE (op) == CONST_DOUBLE
-          && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))
+  else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
     {
-      REAL_VALUE_TYPE r;
       char dstr[30];
 
-      REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);
+      real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
+                      sizeof (dstr), 0, 1);
       asm_fprintf (file, "%I0r%s", dstr);
     }
   else
@@ -2298,25 +2241,24 @@ print_operand (file, op, letter)
       int need_parenthesize = 0;
 
       if (letter != 'i')
-       asm_fprintf (file, "%0I");
+       asm_fprintf (file, "%I");
       else
         need_parenthesize = must_parenthesize (op);
 
       if (need_parenthesize)
-        asm_fprintf (file, "(");
+        fprintf (file, "(");
 
       output_addr_const (file, op);
       if (need_parenthesize)
-        asm_fprintf (file, ")");
+        fprintf (file, ")");
     }
 }
 
 /* Returns true if the operand 'op' must be printed with parenthesis
-   arround it.  This must be done only if there is a symbol whose name
+   around it.  This must be done only if there is a symbol whose name
    is a processor register.  */
 static int
-must_parenthesize (op)
-     rtx op;
+must_parenthesize (rtx op)
 {
   const char *name;
 
@@ -2362,9 +2304,7 @@ must_parenthesize (op)
    reference whose address is ADDR.  ADDR is an RTL expression.  */
 
 void
-print_operand_address (file, addr)
-     FILE *file;
-     rtx addr;
+print_operand_address (FILE *file, rtx addr)
 {
   rtx base;
   rtx offset;
@@ -2373,10 +2313,9 @@ print_operand_address (file, addr)
   switch (GET_CODE (addr))
     {
     case REG:
-      if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
-       abort ();
+      gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
 
-      asm_fprintf (file, "0,");
+      fprintf (file, "0,");
       asm_print_register (file, REGNO (addr));
       break;
 
@@ -2385,55 +2324,39 @@ print_operand_address (file, addr)
       switch (GET_CODE (base))
        {
        case PRE_DEC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
          break;
 
        case POST_DEC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             asm_fprintf (file, "-");
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
+         fprintf (file, "-");
          break;
 
        case POST_INC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             asm_fprintf (file, "+");
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
+         fprintf (file, "+");
          break;
 
        case PRE_INC:
-         if (TARGET_M6812)
-           {
-             asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-           }
-         else
-           abort ();
+         gcc_assert (TARGET_M6812);
+         fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
+         asm_print_register (file, REGNO (XEXP (base, 0)));
          break;
 
        default:
          need_parenthesis = must_parenthesize (base);
          if (need_parenthesis)
-           asm_fprintf (file, "(");
+           fprintf (file, "(");
 
          output_addr_const (file, base);
          if (need_parenthesis)
-           asm_fprintf (file, ")");
+           fprintf (file, ")");
          break;
        }
       break;
@@ -2446,66 +2369,60 @@ print_operand_address (file, addr)
          base = XEXP (addr, 1);
          offset = XEXP (addr, 0);
        }
-      if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
+      if (CONSTANT_ADDRESS_P (base))
        {
          need_parenthesis = must_parenthesize (addr);
 
+         gcc_assert (CONSTANT_ADDRESS_P (offset));
          if (need_parenthesis)
-           asm_fprintf (file, "(");
+           fprintf (file, "(");
 
          output_addr_const (file, base);
-         asm_fprintf (file, "+");
+         fprintf (file, "+");
          output_addr_const (file, offset);
          if (need_parenthesis)
-           asm_fprintf (file, ")");
+           fprintf (file, ")");
        }
-      else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
+      else
        {
+         gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
          if (REG_P (offset))
            {
-             if (TARGET_M6812)
-               {
-                 asm_print_register (file, REGNO (offset));
-                 asm_fprintf (file, ",");
-                 asm_print_register (file, REGNO (base));
-               }
-             else
-               abort ();
+             gcc_assert (TARGET_M6812);
+             asm_print_register (file, REGNO (offset));
+             fprintf (file, ",");
+             asm_print_register (file, REGNO (base));
            }
          else
            {
               need_parenthesis = must_parenthesize (offset);
               if (need_parenthesis)
-                asm_fprintf (file, "(");
+                fprintf (file, "(");
 
              output_addr_const (file, offset);
               if (need_parenthesis)
-                asm_fprintf (file, ")");
-             asm_fprintf (file, ",");
+                fprintf (file, ")");
+             fprintf (file, ",");
              asm_print_register (file, REGNO (base));
            }
        }
-      else
-       {
-         abort ();
-       }
       break;
 
     default:
       if (GET_CODE (addr) == CONST_INT
          && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
        {
-         asm_fprintf (file, "%d", INTVAL (addr));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
        }
       else
        {
          need_parenthesis = must_parenthesize (addr);
          if (need_parenthesis)
-           asm_fprintf (file, "(");
+           fprintf (file, "(");
 
          output_addr_const (file, addr);
          if (need_parenthesis)
-           asm_fprintf (file, ")");
+           fprintf (file, ")");
        }
       break;
     }
@@ -2515,28 +2432,21 @@ print_operand_address (file, addr)
 /* Splitting of some instructions.  */
 
 static rtx
-m68hc11_expand_compare (code, op0, op1)
-     enum rtx_code code;
-     rtx op0, op1;
+m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
 {
   rtx ret = 0;
 
-  if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
-    abort ();
-  else
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
-                             gen_rtx_COMPARE (VOIDmode, op0, op1)));
-      ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
-    }
+  gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
+  emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
+                         gen_rtx_COMPARE (VOIDmode, op0, op1)));
+  ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
 
   return ret;
 }
 
 rtx
-m68hc11_expand_compare_and_branch (code, op0, op1, label)
-     enum rtx_code code;
-     rtx op0, op1, label;
+m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
+                                   rtx label)
 {
   rtx tmp;
 
@@ -2649,15 +2559,15 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label)
            break;
 
          case EQ:
-           code1 = NIL;
+           code1 = UNKNOWN;
            code2 = NE;
            break;
          case NE:
-           code2 = NIL;
+           code2 = UNKNOWN;
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
 
        /*
@@ -2667,20 +2577,20 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label)
         *    if (lo(a) < lo(b)) goto true;
         *  false:
         */
-       if (code1 != NIL)
+       if (code1 != UNKNOWN)
          m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
-       if (code2 != NIL)
+       if (code2 != UNKNOWN)
          m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
 
        m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
 
-       if (code2 != NIL)
+       if (code2 != UNKNOWN)
          emit_label (label2);
        return 0;
       }
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
   return 0;
 }
@@ -2688,8 +2598,7 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label)
 /* Return the increment/decrement mode of a MEM if it is such.
    Return CONST if it is anything else.  */
 static int
-autoinc_mode (x)
-     rtx x;
+autoinc_mode (rtx x)
 {
   if (GET_CODE (x) != MEM)
     return CONST;
@@ -2705,9 +2614,7 @@ autoinc_mode (x)
 }
 
 static int
-m68hc11_make_autoinc_notes (x, data)
-     rtx *x;
-     void *data;
+m68hc11_make_autoinc_notes (rtx *x, void *data)
 {
   rtx insn;
   
@@ -2731,8 +2638,7 @@ m68hc11_make_autoinc_notes (x, data)
    The scratch register 'scratch' is used as a temporary to load
    store intermediate values.  It must be a hard register.  */
 void
-m68hc11_split_move (to, from, scratch)
-     rtx to, from, scratch;
+m68hc11_split_move (rtx to, rtx from, rtx scratch)
 {
   rtx low_to, low_from;
   rtx high_to, high_from;
@@ -2848,7 +2754,7 @@ m68hc11_split_move (to, from, scratch)
 
   if (TARGET_M6812
       && IS_STACK_PUSH (to)
-      && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
+      && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
     {
       if (mode == SImode)
         {
@@ -2866,15 +2772,7 @@ m68hc11_split_move (to, from, scratch)
   high_to = m68hc11_gen_highpart (mode, to);
 
   low_from = m68hc11_gen_lowpart (mode, from);
-  if (mode == SImode && GET_CODE (from) == CONST_INT)
-    {
-      if (INTVAL (from) >= 0)
-       high_from = const0_rtx;
-      else
-       high_from = constm1_rtx;
-    }
-  else
-    high_from = m68hc11_gen_highpart (mode, from);
+  high_from = m68hc11_gen_highpart (mode, from);
 
   if (offset)
     {
@@ -2938,11 +2836,7 @@ m68hc11_split_move (to, from, scratch)
 }
 
 static rtx
-simplify_logical (mode, code, operand, result)
-     enum machine_mode mode;
-     int code;
-     rtx operand;
-     rtx *result;
+simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
 {
   int val;
   int mask;
@@ -2982,10 +2876,7 @@ simplify_logical (mode, code, operand, result)
 }
 
 static void
-m68hc11_emit_logical (mode, code, operands)
-     enum machine_mode mode;
-     int code;
-     rtx *operands;
+m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
 {
   rtx result;
   int need_copy;
@@ -3016,18 +2907,19 @@ m68hc11_emit_logical (mode, code, operands)
       if (!H_REG_P (operands[0]) && operands[3])
        {
          emit_move_insn (operands[3], operands[1]);
-         emit_insn (gen_rtx (SET, mode,
-                             operands[3],
-                             gen_rtx (code, mode,
-                                      operands[3], operands[2])));
+         emit_insn (gen_rtx_SET (mode,
+                                 operands[3],
+                                 gen_rtx_fmt_ee (code, mode,
+                                                 operands[3], operands[2])));
          insn = emit_move_insn (operands[0], operands[3]);
        }
       else
        {
-         insn = emit_insn (gen_rtx (SET, mode,
-                                    operands[0],
-                                    gen_rtx (code, mode,
-                                             operands[0], operands[2])));
+         insn = emit_insn (gen_rtx_SET (mode,
+                                        operands[0],
+                                        gen_rtx_fmt_ee (code, mode,
+                                                        operands[0],
+                                                        operands[2])));
        }
     }
 
@@ -3054,10 +2946,7 @@ m68hc11_emit_logical (mode, code, operands)
 }
 
 void
-m68hc11_split_logical (mode, code, operands)
-     enum machine_mode mode;
-     int code;
-     rtx *operands;
+m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
 {
   rtx low[4];
   rtx high[4];
@@ -3067,26 +2956,8 @@ m68hc11_split_logical (mode, code, operands)
   low[2] = m68hc11_gen_lowpart (mode, operands[2]);
 
   high[0] = m68hc11_gen_highpart (mode, operands[0]);
-
-  if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
-    {
-      if (INTVAL (operands[1]) >= 0)
-       high[1] = const0_rtx;
-      else
-       high[1] = constm1_rtx;
-    }
-  else
-    high[1] = m68hc11_gen_highpart (mode, operands[1]);
-
-  if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
-    {
-      if (INTVAL (operands[2]) >= 0)
-       high[2] = const0_rtx;
-      else
-       high[2] = constm1_rtx;
-    }
-  else
-    high[2] = m68hc11_gen_highpart (mode, operands[2]);
+  high[1] = m68hc11_gen_highpart (mode, operands[1]);
+  high[2] = m68hc11_gen_highpart (mode, operands[2]);
 
   low[3] = operands[3];
   high[3] = operands[3];
@@ -3105,9 +2976,7 @@ m68hc11_split_logical (mode, code, operands)
 /* Code generation.  */
 
 void
-m68hc11_output_swap (insn, operands)
-     rtx insn ATTRIBUTE_UNUSED;
-     rtx operands[];
+m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
 {
   /* We have to be careful with the cc_status.  An address register swap
      is generated for some comparison.  The comparison is made with D
@@ -3123,10 +2992,10 @@ m68hc11_output_swap (insn, operands)
        {
          cc_status = cc_prev_status;
          if (D_REG_P (cc_status.value1))
-           cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
+           cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
                                        HARD_X_REGNUM);
          else
-           cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
+           cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
                                        HARD_D_REGNUM);
        }
       else
@@ -3142,10 +3011,10 @@ m68hc11_output_swap (insn, operands)
        {
          cc_status = cc_prev_status;
          if (D_REG_P (cc_status.value1))
-           cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
+           cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
                                        HARD_Y_REGNUM);
          else
-           cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
+           cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
                                        HARD_D_REGNUM);
        }
       else
@@ -3159,9 +3028,7 @@ m68hc11_output_swap (insn, operands)
    This is used to decide whether a move that set flags should be used
    instead.  */
 int
-next_insn_test_reg (insn, reg)
-     rtx insn;
-     rtx reg;
+next_insn_test_reg (rtx insn, rtx reg)
 {
   rtx body;
 
@@ -3182,9 +3049,7 @@ next_insn_test_reg (insn, reg)
 /* Generate the code to move a 16-bit operand into another one.  */
 
 void
-m68hc11_gen_movhi (insn, operands)
-     rtx insn;
-     rtx *operands;
+m68hc11_gen_movhi (rtx insn, rtx *operands)
 {
   int reg;
 
@@ -3199,10 +3064,13 @@ m68hc11_gen_movhi (insn, operands)
 
   if (TARGET_M6812)
     {
-      if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
+      rtx from = operands[1];
+      rtx to = operands[0];
+
+      if (IS_STACK_PUSH (to) && H_REG_P (from))
        {
           cc_status = cc_prev_status;
-         switch (REGNO (operands[1]))
+         switch (REGNO (from))
            {
            case HARD_X_REGNUM:
            case HARD_Y_REGNUM:
@@ -3210,17 +3078,17 @@ m68hc11_gen_movhi (insn, operands)
              output_asm_insn ("psh%1", operands);
              break;
             case HARD_SP_REGNUM:
-              output_asm_insn ("sts\t-2,sp", operands);
+              output_asm_insn ("sts\t2,-sp", operands);
               break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
          return;
        }
-      if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
+      if (IS_STACK_POP (from) && H_REG_P (to))
        {
           cc_status = cc_prev_status;
-         switch (REGNO (operands[0]))
+         switch (REGNO (to))
            {
            case HARD_X_REGNUM:
            case HARD_Y_REGNUM:
@@ -3228,7 +3096,7 @@ m68hc11_gen_movhi (insn, operands)
              output_asm_insn ("pul%0", operands);
              break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
          return;
        }
@@ -3251,11 +3119,52 @@ m68hc11_gen_movhi (insn, operands)
          else
            output_asm_insn ("st%1\t%0", operands);
        }
+
+      /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
+         instruction.  We have to use a scratch register as temporary location.
+         Trying to use a specific pattern or constrain failed.  */
+      else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
+        {
+          rtx ops[4];
+
+          ops[0] = to;
+          ops[2] = from;
+          ops[3] = 0;
+          if (dead_register_here (insn, d_reg))
+            ops[1] = d_reg;
+          else if (dead_register_here (insn, ix_reg))
+            ops[1] = ix_reg;
+          else if (dead_register_here (insn, iy_reg))
+            ops[1] = iy_reg;
+          else
+            {
+              ops[1] = d_reg;
+              ops[3] = d_reg;
+              output_asm_insn ("psh%3", ops);
+            }
+
+          ops[0] = to;
+          ops[2] = from;
+          output_asm_insn ("ld%1\t%2", ops);
+          output_asm_insn ("st%1\t%0", ops);
+          if (ops[3])
+            output_asm_insn ("pul%3", ops);
+        }
+
+      /* Use movw for non-null constants or when we are clearing
+         a volatile memory reference.  However, this is possible
+         only if the memory reference has a small offset or is an
+         absolute address.  */
+      else if (GET_CODE (from) == CONST_INT
+               && INTVAL (from) == 0
+               && (MEM_VOLATILE_P (to) == 0
+                   || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
+        {
+          output_asm_insn ("clr\t%h0", operands);
+          output_asm_insn ("clr\t%b0", operands);
+        }
       else
        {
-         rtx from = operands[1];
-         rtx to = operands[0];
-
          if ((m68hc11_register_indirect_p (from, GET_MODE (from))
               && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
              || (m68hc11_register_indirect_p (to, GET_MODE (to))
@@ -3272,6 +3181,7 @@ m68hc11_gen_movhi (insn, operands)
                  ops[0] = to;
                  ops[1] = operands[2];
                  m68hc11_gen_movhi (insn, ops);
+                  return;
                }
              else
                {
@@ -3279,19 +3189,11 @@ m68hc11_gen_movhi (insn, operands)
                   fatal_insn ("move insn not handled", insn);
                }
            }
-         else
-           {
-             if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
-               {
-                 output_asm_insn ("clr\t%h0", operands);
-                 output_asm_insn ("clr\t%b0", operands);
-               }
-             else
-               {
-                  m68hc11_notice_keep_cc (operands[0]);
-                 output_asm_insn ("movw\t%1,%0", operands);
-               }
-           }
+          else
+            {
+              m68hc11_notice_keep_cc (operands[0]);
+              output_asm_insn ("movw\t%1,%0", operands);
+            }
        }
       return;
     }
@@ -3310,7 +3212,7 @@ m68hc11_gen_movhi (insn, operands)
          output_asm_insn ("pulb", operands);
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     }
@@ -3406,11 +3308,17 @@ m68hc11_gen_movhi (insn, operands)
                   output_asm_insn ("xgdx", operands);
                   CC_STATUS_INIT;
                 }
-              else
+              else if (!optimize_size)
                 {
                   output_asm_insn ("sty\t%t1", operands);
                   output_asm_insn ("ldx\t%t1", operands);
                 }
+              else
+                {
+                  CC_STATUS_INIT;
+                  output_asm_insn ("pshy", operands);
+                  output_asm_insn ("pulx", operands);
+                }
            }
          else if (SP_REG_P (operands[1]))
            {
@@ -3448,11 +3356,17 @@ m68hc11_gen_movhi (insn, operands)
                   output_asm_insn ("xgdy", operands);
                   CC_STATUS_INIT;
                 }
-              else
+              else if (!optimize_size)
                 {
                   output_asm_insn ("stx\t%t1", operands);
                   output_asm_insn ("ldy\t%t1", operands);
                 }
+              else
+                {
+                  CC_STATUS_INIT;
+                  output_asm_insn ("pshx", operands);
+                  output_asm_insn ("puly", operands);
+                }
            }
          else if (SP_REG_P (operands[1]))
            {
@@ -3460,7 +3374,7 @@ m68hc11_gen_movhi (insn, operands)
              cc_status = cc_prev_status;
              output_asm_insn ("tsy", operands);
            }
-         else
+          else
            {
              output_asm_insn ("ldy\t%1", operands);
            }
@@ -3522,7 +3436,7 @@ m68hc11_gen_movhi (insn, operands)
          output_asm_insn ("psha", operands);
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     }
@@ -3586,9 +3500,7 @@ m68hc11_gen_movhi (insn, operands)
 }
 
 void
-m68hc11_gen_movqi (insn, operands)
-     rtx insn;
-     rtx *operands;
+m68hc11_gen_movqi (rtx insn, rtx *operands)
 {
   /* Move a register or memory to the same location.
      This is possible because such insn can appear
@@ -3609,8 +3521,10 @@ m68hc11_gen_movqi (insn, operands)
        }
       else if (H_REG_P (operands[0]))
        {
-         if (Q_REG_P (operands[0]))
-           output_asm_insn ("lda%0\t%b1", operands);
+          if (IS_STACK_POP (operands[1]))
+            output_asm_insn ("pul%b0", operands);
+         else if (Q_REG_P (operands[0]))
+            output_asm_insn ("lda%0\t%b1", operands);
          else if (D_REG_P (operands[0]))
            output_asm_insn ("ldab\t%b1", operands);
          else
@@ -3868,10 +3782,7 @@ m68hc11_gen_movqi (insn, operands)
    The source and destination must be D or A and the shift must
    be a constant.  */
 void
-m68hc11_gen_rotate (code, insn, operands)
-     enum rtx_code code;
-     rtx insn;
-     rtx operands[];
+m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
 {
   int val;
   
@@ -3908,15 +3819,15 @@ m68hc11_gen_rotate (code, insn, operands)
 
   if (val > 0)
     {
-      /* Set the carry to bit-15, but don't change D yet.  */
-      if (GET_MODE (operands[0]) != QImode)
-        {
-          output_asm_insn ("asra", operands);
-          output_asm_insn ("rola", operands);
-        }
-
       while (--val >= 0)
         {
+          /* Set the carry to bit-15, but don't change D yet.  */
+          if (GET_MODE (operands[0]) != QImode)
+            {
+              output_asm_insn ("asra", operands);
+              output_asm_insn ("rola", operands);
+            }
+
           /* Rotate B first to move the carry to bit-0.  */
           if (D_REG_P (operands[0]))
             output_asm_insn ("rolb", operands);
@@ -3927,14 +3838,12 @@ m68hc11_gen_rotate (code, insn, operands)
     }
   else
     {
-      /* Set the carry to bit-8 of D.  */
-      if (val != 0 && GET_MODE (operands[0]) != QImode)
-        {
-          output_asm_insn ("tap", operands);
-        }
-      
       while (++val <= 0)
         {
+          /* Set the carry to bit-8 of D.  */
+          if (GET_MODE (operands[0]) != QImode)
+            output_asm_insn ("tap", operands);
+
           /* Rotate B first to move the carry to bit-7.  */
           if (D_REG_P (operands[0]))
             output_asm_insn ("rorb", operands);
@@ -3952,9 +3861,7 @@ m68hc11_gen_rotate (code, insn, operands)
    Do not alter them if the instruction would not alter the cc's.  */
 
 void
-m68hc11_notice_update_cc (exp, insn)
-     rtx exp;
-     rtx insn ATTRIBUTE_UNUSED;
+m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
 {
   /* recognize SET insn's.  */
   if (GET_CODE (exp) == SET)
@@ -4048,14 +3955,19 @@ m68hc11_notice_update_cc (exp, insn)
       && cc_status.value2
       && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
     cc_status.value2 = 0;
+
+  else if (cc_status.value1 && side_effects_p (cc_status.value1))
+    cc_status.value1 = 0;
+
+  else if (cc_status.value2 && side_effects_p (cc_status.value2))
+    cc_status.value2 = 0;
 }
 
 /* The current instruction does not affect the flags but changes
    the register 'reg'.  See if the previous flags can be kept for the
    next instruction to avoid a comparison.  */
 void
-m68hc11_notice_keep_cc (reg)
-     rtx reg;
+m68hc11_notice_keep_cc (rtx reg)
 {
   if (reg == 0
       || cc_prev_status.value1 == 0
@@ -4130,12 +4042,10 @@ struct replace_info
   int z_loaded_with_sp;
 };
 
-static rtx z_reg_qi;
-
-static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
-static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
-static void m68hc11_z_replacement PARAMS ((rtx));
-static void m68hc11_reassign_regs PARAMS ((rtx));
+static int m68hc11_check_z_replacement (rtx, struct replace_info *);
+static void m68hc11_find_z_replacement (rtx, struct replace_info *);
+static void m68hc11_z_replacement (rtx);
+static void m68hc11_reassign_regs (rtx);
 
 int z_replacement_completed = 0;
 
@@ -4145,9 +4055,7 @@ int z_replacement_completed = 0;
    continue replacement in next insns.  */
 
 static int
-m68hc11_check_z_replacement (insn, info)
-     rtx insn;
-     struct replace_info *info;
+m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
 {
   int this_insn_uses_ix;
   int this_insn_uses_iy;
@@ -4220,8 +4128,10 @@ m68hc11_check_z_replacement (insn, info)
        {
          if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
              || (GET_CODE (src) == COMPARE &&
-                 (rtx_equal_p (XEXP (src, 0), z_reg)
-                  || rtx_equal_p (XEXP (src, 1), z_reg))))
+                 ((rtx_equal_p (XEXP (src, 0), z_reg)
+                    && H_REG_P (XEXP (src, 1)))
+                  || (rtx_equal_p (XEXP (src, 1), z_reg)
+                       && H_REG_P (XEXP (src, 0))))))
            {
              if (insn == info->first)
                {
@@ -4231,7 +4141,7 @@ m68hc11_check_z_replacement (insn, info)
                  info->need_save_z = 0;
                  info->found_call = 1;
                  info->regno = SOFT_Z_REGNUM;
-                 info->last = insn;
+                 info->last = NEXT_INSN (insn);
                }
              return 0;
            }
@@ -4337,9 +4247,7 @@ m68hc11_check_z_replacement (insn, info)
                  info->must_restore_reg = 0;
                  info->found_call = 1;
                  info->can_use_d = 0;
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
+                 SET_INSN_DELETED (insn);
                  info->last = NEXT_INSN (insn);
                  return 0;
                }
@@ -4365,7 +4273,13 @@ m68hc11_check_z_replacement (insn, info)
                      info->z_died = 1;
                      info->need_save_z = 0;
                    }
-                 else
+                 else if (TARGET_M6812 && side_effects_p (src))
+                    {
+                      info->last = 0;
+                      info->must_restore_reg = 0;
+                      return 0;
+                    }
+                  else
                    {
                      info->save_before_last = 1;
                    }
@@ -4414,9 +4328,7 @@ m68hc11_check_z_replacement (insn, info)
                  info->must_restore_reg = 0;
                  info->found_call = 1;
                  info->can_use_d = 0;
-                 PUT_CODE (insn, NOTE);
-                 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-                 NOTE_SOURCE_FILE (insn) = 0;
+                 SET_INSN_DELETED (insn);
                  info->last = NEXT_INSN (insn);
                  return 0;
                }
@@ -4442,7 +4354,13 @@ m68hc11_check_z_replacement (insn, info)
                      info->z_died = 1;
                      info->need_save_z = 0;
                    }
-                 else
+                 else if (TARGET_M6812 && side_effects_p (src))
+                    {
+                      info->last = 0;
+                      info->must_restore_reg = 0;
+                      return 0;
+                    }
+                  else
                    {
                      info->save_before_last = 1;
                    }
@@ -4698,9 +4616,7 @@ m68hc11_check_z_replacement (insn, info)
 }
 
 static void
-m68hc11_find_z_replacement (insn, info)
-     rtx insn;
-     struct replace_info *info;
+m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
 {
   int reg;
 
@@ -4775,7 +4691,7 @@ m68hc11_find_z_replacement (insn, info)
   if (info->regno >= 0)
     {
       reg = info->regno;
-      info->replace_reg = gen_rtx (REG, HImode, reg);
+      info->replace_reg = gen_rtx_REG (HImode, reg);
     }
   else if (info->can_use_d)
     {
@@ -4807,12 +4723,11 @@ m68hc11_find_z_replacement (insn, info)
 /* The insn uses the Z register.  Find a replacement register for it
    (either X or Y) and replace it in the insn and the next ones until
    the flow changes or the replacement register is used.  Instructions
-   are emited before and after the Z-block to preserve the value of
+   are emitted before and after the Z-block to preserve the value of
    Z and of the replacement register.  */
 
 static void
-m68hc11_z_replacement (insn)
-     rtx insn;
+m68hc11_z_replacement (rtx insn)
 {
   rtx replace_reg_qi;
   rtx replace_reg;
@@ -4828,26 +4743,26 @@ m68hc11_z_replacement (insn)
 
       if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
        {
-         XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
+         XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
          return;
        }
       else if (Z_REG_P (src)
               && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
        {
-         XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
+         XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
          return;
        }
       else if (D_REG_P (dst)
               && m68hc11_arith_operator (src, GET_MODE (src))
               && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
        {
-         XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
+         XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
          return;
        }
       else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
               && INTVAL (src) == 0)
        {
-         XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
+         XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
           /* Force it to be re-recognized.  */
           INSN_CODE (insn) = -1;
          return;
@@ -4865,19 +4780,19 @@ m68hc11_z_replacement (insn)
       rtx dst;
 
       if (info.must_push_reg && 0)
-       dst = gen_rtx (MEM, HImode,
-                      gen_rtx (PRE_DEC, HImode,
-                               gen_rtx (REG, HImode, HARD_SP_REGNUM)));
+       dst = gen_rtx_MEM (HImode,
+                      gen_rtx_PRE_DEC (HImode,
+                               gen_rtx_REG (HImode, HARD_SP_REGNUM)));
       else
-       dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
+       dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
 
       emit_insn_before (gen_movhi (dst,
-                                  gen_rtx (REG, HImode, info.regno)), insn);
+                                  gen_rtx_REG (HImode, info.regno)), insn);
     }
   if (info.must_load_z && !info.must_push_reg)
     {
-      emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
-                                  gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
+      emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
+                                  gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
                        insn);
     }
 
@@ -4900,6 +4815,7 @@ m68hc11_z_replacement (insn)
 
       body = PATTERN (insn);
       if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
+          || GET_CODE (body) == ASM_OPERANDS
          || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
        {
           rtx note;
@@ -4936,7 +4852,7 @@ m68hc11_z_replacement (insn)
          if (reg_mentioned_p (z_reg, insn))
            {
              if (replace_reg_qi == NULL_RTX)
-               replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
+               replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
              validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
            }
 
@@ -4968,8 +4884,8 @@ m68hc11_z_replacement (insn)
       if (info.save_before_last)
        save_pos_insn = PREV_INSN (save_pos_insn);
 
-      emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
-                                  gen_rtx (REG, HImode, info.regno)),
+      emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
+                                  gen_rtx_REG (HImode, info.regno)),
                        save_pos_insn);
     }
 
@@ -4978,12 +4894,12 @@ m68hc11_z_replacement (insn)
       rtx new_body, body;
 
       body = PATTERN (info.last);
-      new_body = gen_rtx (PARALLEL, VOIDmode,
+      new_body = gen_rtx_PARALLEL (VOIDmode,
                          gen_rtvec (3, body,
-                                    gen_rtx (USE, VOIDmode,
+                                    gen_rtx_USE (VOIDmode,
                                              replace_reg),
-                                    gen_rtx (USE, VOIDmode,
-                                             gen_rtx (REG, HImode,
+                                    gen_rtx_USE (VOIDmode,
+                                             gen_rtx_REG (HImode,
                                                       SOFT_Z_REGNUM))));
       PATTERN (info.last) = new_body;
 
@@ -5003,13 +4919,13 @@ m68hc11_z_replacement (insn)
       rtx dst;
 
       if (info.must_push_reg && 0)
-       dst = gen_rtx (MEM, HImode,
-                      gen_rtx (POST_INC, HImode,
-                               gen_rtx (REG, HImode, HARD_SP_REGNUM)));
+       dst = gen_rtx_MEM (HImode,
+                      gen_rtx_POST_INC (HImode,
+                               gen_rtx_REG (HImode, HARD_SP_REGNUM)));
       else
-       dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
+       dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
 
-      emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
+      emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
                                   dst), insn);
     }
 
@@ -5021,15 +4937,14 @@ m68hc11_z_replacement (insn)
       on the instruction.  */
 
 static void
-m68hc11_reassign_regs (first)
-     rtx first;
+m68hc11_reassign_regs (rtx first)
 {
   rtx insn;
 
-  ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
-  iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
-  z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
-  z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
+  ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
+  iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
+  z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
+  z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
 
   /* Scan all insns to replace Z by X or Y preserving the old value
      of X/Y and restoring it afterward.  */
@@ -5042,7 +4957,7 @@ m68hc11_reassign_regs (first)
          || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
        continue;
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+      if (!INSN_P (insn))
        continue;
 
       body = PATTERN (insn);
@@ -5077,21 +4992,29 @@ m68hc11_reassign_regs (first)
 }
 
 
-void
-m68hc11_reorg (first)
-     rtx first;
+/* Machine-dependent reorg pass.
+   Specific optimizations are defined here:
+    - this pass changes the Z register into either X or Y
+      (it preserves X/Y previous values in a memory slot in page0).
+
+   When this pass is finished, the global variable
+   'z_replacement_completed' is set to 2.  */
+
+static void
+m68hc11_reorg (void)
 {
   int split_done = 0;
-  rtx insn;
+  rtx first;
 
   z_replacement_completed = 0;
-  z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
+  z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
+  first = get_insns ();
 
   /* Some RTX are shared at this point.  This breaks the Z register
      replacement, unshare everything.  */
   unshare_all_rtl_again (first);
 
-  /* Force a split of all splitable insn.  This is necessary for the
+  /* Force a split of all splittable insn.  This is necessary for the
      Z register replacement mechanism because we end up with basic insns.  */
   split_all_insns_noflow ();
   split_done = 1;
@@ -5099,11 +5022,13 @@ m68hc11_reorg (first)
   z_replacement_completed = 1;
   m68hc11_reassign_regs (first);
 
-  /* After some splitting, there are some oportunities for CSE pass.
+  if (optimize)
+    compute_bb_for_insn ();
+
+  /* After some splitting, there are some opportunities for CSE pass.
      This happens quite often when 32-bit or above patterns are split.  */
   if (optimize > 0 && split_done)
     {
-      find_basic_blocks (first, max_reg_num (), 0);
       reload_cse_regs (first);
     }
 
@@ -5111,30 +5036,9 @@ m68hc11_reorg (first)
      description to use the best assembly directives.  */
   if (optimize)
     {
-      /* Before recomputing the REG_DEAD notes, remove all of them.
-         This is necessary because the reload_cse_regs() pass can
-         have replaced some (MEM) with a register.  In that case,
-         the REG_DEAD that could exist for that register may become
-         wrong.  */
-      for (insn = first; insn; insn = NEXT_INSN (insn))
-        {
-          if (INSN_P (insn))
-            {
-              rtx *pnote;
-
-              pnote = &REG_NOTES (insn);
-              while (*pnote != 0)
-                {
-                  if (REG_NOTE_KIND (*pnote) == REG_DEAD)
-                    *pnote = XEXP (*pnote, 1);
-                  else
-                    pnote = &XEXP (*pnote, 1);
-                }
-            }
-        }
-
-      find_basic_blocks (first, max_reg_num (), 0);
-      life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
+      df_note_add_problem ();
+      df_analyze ();
+      df_remove_problem (df_note);
     }
 
   z_replacement_completed = 2;
@@ -5162,7 +5066,7 @@ m68hc11_reorg (first)
 
        if (INSN_DELETED_P (insn))
          continue;
-       if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+       if (!INSN_P (insn))
          continue;
 
        /* Remove the (set (R) (R)) insns generated by some splits.  */
@@ -5170,26 +5074,33 @@ m68hc11_reorg (first)
        if (GET_CODE (body) == SET
            && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
          {
-           PUT_CODE (insn, NOTE);
-           NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-           NOTE_SOURCE_FILE (insn) = 0;
+           SET_INSN_DELETED  (insn);
            continue;
          }
       }
   }
 }
+\f
+/* Override memcpy */
+
+static void
+m68hc11_init_libfuncs (void)
+{
+  memcpy_libfunc = init_one_libfunc ("__memcpy");
+  memcmp_libfunc = init_one_libfunc ("__memcmp");
+  memset_libfunc = init_one_libfunc ("__memset");
+}
+
 \f
 
 /* Cost functions.  */
 
 /* Cost of moving memory.  */
 int
-m68hc11_memory_move_cost (mode, class, in)
-     enum machine_mode mode;
-     enum reg_class class;
-     int in ATTRIBUTE_UNUSED;
+m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
+                          int in ATTRIBUTE_UNUSED)
 {
-  if (class <= H_REGS && class > NO_REGS)
+  if (rclass <= H_REGS && rclass > NO_REGS)
     {
       if (GET_MODE_SIZE (mode) <= 2)
        return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
@@ -5199,7 +5110,7 @@ m68hc11_memory_move_cost (mode, class, in)
   else
     {
       if (GET_MODE_SIZE (mode) <= 2)
-       return COSTS_N_INSNS (2);
+       return COSTS_N_INSNS (3);
       else
        return COSTS_N_INSNS (4);
     }
@@ -5211,10 +5122,8 @@ m68hc11_memory_move_cost (mode, class, in)
    have a move cost of 2.  Setting a higher cost will force reload to check
    the constraints.  */
 int
-m68hc11_register_move_cost (mode, from, to)
-     enum machine_mode mode;
-     enum reg_class from;
-     enum reg_class to;
+m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
+                            enum reg_class to)
 {
   /* All costs are symmetric, so reduce cases by putting the
      lower number class as the destination.  */
@@ -5235,9 +5144,8 @@ m68hc11_register_move_cost (mode, from, to)
 /* Provide the costs of an addressing mode that contains ADDR.
    If ADDR is not a valid address, its cost is irrelevant.  */
 
-int
-m68hc11_address_cost (addr)
-     rtx addr;
+static int
+m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
 {
   int cost = 4;
 
@@ -5318,14 +5226,11 @@ m68hc11_address_cost (addr)
 }
 
 static int
-m68hc11_shift_cost (mode, x, shift)
-     enum machine_mode mode;
-     rtx x;
-     int shift;
+m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
 {
   int total;
 
-  total = rtx_cost (x, SET);
+  total = rtx_cost (x, SET, !optimize_size);
   if (mode == QImode)
     total += m68hc11_cost->shiftQI_const[shift % 8];
   else if (mode == HImode)
@@ -5349,11 +5254,9 @@ m68hc11_shift_cost (mode, x, shift)
   return total;
 }
 
-int
-m68hc11_rtx_costs (x, code, outer_code)
-     rtx x;
-     enum rtx_code code;
-     enum rtx_code outer_code ATTRIBUTE_UNUSED;
+static int
+m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
+                     enum rtx_code outer_code ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode = GET_MODE (x);
   int extra_cost = 0;
@@ -5371,14 +5274,14 @@ m68hc11_rtx_costs (x, code, outer_code)
           return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
        }
 
-      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
+      total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
       total += m68hc11_cost->shift_var;
       return total;
 
     case AND:
     case XOR:
     case IOR:
-      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
+      total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
       total += m68hc11_cost->logical;
 
       /* Logical instructions are byte instructions only.  */
@@ -5387,7 +5290,7 @@ m68hc11_rtx_costs (x, code, outer_code)
 
     case MINUS:
     case PLUS:
-      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
+      total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
       total += m68hc11_cost->add;
       if (GET_MODE_SIZE (mode) > 2)
        {
@@ -5398,7 +5301,7 @@ m68hc11_rtx_costs (x, code, outer_code)
     case UDIV:
     case DIV:
     case MOD:
-      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
+      total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
       switch (mode)
         {
         case QImode:
@@ -5421,18 +5324,19 @@ m68hc11_rtx_costs (x, code, outer_code)
       if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
           && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
         return m68hc11_cost->multQI
-          + rtx_cost (XEXP (XEXP (x, 0), 0), code)
-          + rtx_cost (XEXP (XEXP (x, 1), 0), code);
+          + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
+          + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
 
       /* emul instruction produces 32-bit result for 68HC12.  */
       if (TARGET_M6812 && mode == SImode
           && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
           && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
         return m68hc11_cost->multHI
-          + rtx_cost (XEXP (XEXP (x, 0), 0), code)
-          + rtx_cost (XEXP (XEXP (x, 1), 0), code);
+          + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
+          + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
 
-      total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
+      total = rtx_cost (XEXP (x, 0), code, !optimize_size)
+             + rtx_cost (XEXP (x, 1), code, !optimize_size);
       switch (mode)
         {
         case QImode:
@@ -5459,7 +5363,7 @@ m68hc11_rtx_costs (x, code, outer_code)
     case COMPARE:
     case ABS:
     case ZERO_EXTEND:
-      total = extra_cost + rtx_cost (XEXP (x, 0), code);
+      total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
       if (mode == QImode)
        {
          return total + COSTS_N_INSNS (1);
@@ -5484,89 +5388,112 @@ m68hc11_rtx_costs (x, code, outer_code)
       return COSTS_N_INSNS (4);
     }
 }
-\f
 
-/* print_options - called at the start of the code generation for a
-   module.  */
-
-extern char *asm_file_name;
-
-#include <time.h>
-#include <sys/types.h>
-
-static void
-print_options (out)
-     FILE *out;
+static bool
+m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total,
+                  bool speed ATTRIBUTE_UNUSED)
 {
-  const char *a_time;
-  long c_time;
-  int i;
-  extern int save_argc;
-  extern char **save_argv;
-
-  fprintf (out, ";;; Command:\t");
-  for (i = 0; i < save_argc; i++)
-    {
-      fprintf (out, "%s", save_argv[i]);
-      if (i + 1 < save_argc)
-       fprintf (out, " ");
-    }
-  fprintf (out, "\n");
-  c_time = time (0);
-  a_time = ctime (&c_time);
-  fprintf (out, ";;; Compiled:\t%s", a_time);
-#ifdef __GNUC__
-#ifndef __VERSION__
-#define __VERSION__ "[unknown]"
-#endif
-  fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
-#else
-  fprintf (out, ";;; (META)compiled by CC.\n");
-#endif
-}
+  switch (code)
+    {
+      /* Constants are cheap.  Moving them in registers must be avoided
+         because most instructions do not handle two register operands.  */
+    case CONST_INT:
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_DOUBLE:
+      /* Logical and arithmetic operations with a constant operand are
+        better because they are not supported with two registers.  */
+      /* 'clr' is slow */
+      if (outer_code == SET && x == const0_rtx)
+        /* After reload, the reload_cse pass checks the cost to change
+           a SET into a PLUS.  Make const0 cheap then.  */
+       *total = 1 - reload_completed;
+      else
+       *total = 0;
+      return true;
+    
+    case ROTATE:
+    case ROTATERT:
+    case ASHIFT:
+    case LSHIFTRT:
+    case ASHIFTRT:
+    case MINUS:
+    case PLUS:
+    case AND:
+    case XOR:
+    case IOR:
+    case UDIV:
+    case DIV:
+    case MOD:
+    case MULT:
+    case NEG:
+    case SIGN_EXTEND:
+    case NOT:
+    case COMPARE:
+    case ZERO_EXTEND:
+    case IF_THEN_ELSE:
+      *total = m68hc11_rtx_costs_1 (x, code, outer_code);
+      return true;
 
-void
-m68hc11_asm_file_start (out, main_file)
-     FILE *out;
-     const char *main_file;
-{
-  fprintf (out, ";;;-----------------------------------------\n");
-  fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
-  fprintf (out, ";;; gcc compiler %s\n", version_string);
-  print_options (out);
-  fprintf (out, ";;;-----------------------------------------\n");
-  output_file_directive (out, main_file);
+    default:
+      return false;
+    }
 }
+\f
 
+/* Worker function for TARGET_ASM_FILE_START.  */
 
 static void
-m68hc11_add_gc_roots ()
+m68hc11_file_start (void)
 {
-  ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
-  ggc_add_rtx_root (&ix_reg, 1);
-  ggc_add_rtx_root (&iy_reg, 1);
-  ggc_add_rtx_root (&d_reg, 1);
-  ggc_add_rtx_root (&da_reg, 1);
-  ggc_add_rtx_root (&z_reg, 1);
-  ggc_add_rtx_root (&z_reg_qi, 1);
-  ggc_add_rtx_root (&stack_push_word, 1);
-  ggc_add_rtx_root (&stack_pop_word, 1);
+  default_file_start ();
+  
+  fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
 }
 
+
+/* Worker function for TARGET_ASM_CONSTRUCTOR.  */
+
 static void
-m68hc11_asm_out_constructor (symbol, priority)
-     rtx symbol;
-     int priority;
+m68hc11_asm_out_constructor (rtx symbol, int priority)
 {
   default_ctor_section_asm_out_constructor (symbol, priority);
   fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
 }
 
+/* Worker function for TARGET_ASM_DESTRUCTOR.  */
+
 static void
-m68hc11_asm_out_destructor (symbol, priority)
-     rtx symbol;
-     int priority;
+m68hc11_asm_out_destructor (rtx symbol, int priority)
 {
   default_dtor_section_asm_out_destructor (symbol, priority);
   fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
 }
+
+/* Worker function for TARGET_STRUCT_VALUE_RTX.  */
+
+static rtx
+m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+                         int incoming ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (Pmode, HARD_D_REGNUM);
+}
+
+/* Return true if type TYPE should be returned in memory.
+   Blocks and data types largers than 4 bytes cannot be returned
+   in the register (D + X = 4).  */
+
+static bool
+m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  if (TYPE_MODE (type) == BLKmode)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      return (size == -1 || size > 4);
+    }
+  else
+    return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
+}
+
+#include "gt-m68hc11.h"