m68hc11.c (m68hc11_print_operand): Call m68hc11_print_operand_address.
[gcc.git] / gcc / config / m68hc11 / m68hc11.c
index 0e2f6233ae93fd7b42c6ce9bc4022db63a390ddc..e45a74892c6471b45be515bad178c279a16e2a6e 100644 (file)
@@ -1,23 +1,23 @@
 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
-   Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009, 2010 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)
@@ -39,10 +39,10 @@ Note:
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "expr.h"
 #include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "output.h"
@@ -50,6 +50,8 @@ Note:
 #include "flags.h"
 #include "recog.h"
 #include "expr.h"
+#include "libfuncs.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "basic-block.h"
 #include "function.h"
@@ -57,34 +59,44 @@ 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 void m68hc11_reorg PARAMS ((void));
-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_address_cost PARAMS ((rtx));
-static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
-static int m68hc11_rtx_costs_1 PARAMS ((rtx, enum rtx_code, enum rtx_code));
-static bool m68hc11_rtx_costs PARAMS ((rtx, int, int, int *));
-static int m68hc11_auto_inc_p PARAMS ((rtx));
-static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
-const struct attribute_spec m68hc11_attribute_table[];
-
-void create_regs_rtx 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));
-static void m68hc11_encode_section_info PARAMS((tree, rtx, int));
-static int autoinc_mode PARAMS((rtx));
-static int m68hc11_make_autoinc_notes PARAMS((rtx *, void *));
+#include "df.h"
+
+static void m68hc11_option_override (void);
+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, enum rtx_code, rtx *);
+static void m68hc11_reorg (void);
+static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
+static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
+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 *);
+static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
+static bool m68hc11_class_likely_spilled_p (reg_class_t);
+
+void create_regs_rtx (void);
+
+static void asm_print_register (FILE *, int);
+static void m68hc11_print_operand (FILE *, rtx, int);
+static void m68hc11_print_operand_address (FILE *, rtx);
+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);
+static bool m68hc11_can_eliminate (const int, const int);
+static void m68hc11_trampoline_init (rtx, tree, rtx);
 
 /* Must be set to 1 to produce debug messages.  */
 int debug_m6811 = 0;
@@ -135,9 +147,8 @@ unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
    This is 1 for 68HC11 and 0 for 68HC12.  */
 int m68hc11_sp_correction;
 
-/* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns.  */
-rtx m68hc11_compare_op0;
-rtx m68hc11_compare_op1;
+int m68hc11_addr_mode;
+int m68hc11_mov_addr_mode;
 \f
 
 const struct processor_costs *m68hc11_cost;
@@ -211,14 +222,19 @@ static const struct processor_costs m6812_cost = {
   /* divSI */
   COSTS_N_INSNS (100)
 };
+\f
+/* M68HC11 specific attributes.  */
 
-/* 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;
+static 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 }
+};
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -227,12 +243,28 @@ static int nb_soft_regs;
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
 
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND m68hc11_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
+
 #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
@@ -241,10 +273,38 @@ static int nb_soft_regs;
 #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
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P    m68hc11_legitimate_address_p
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
+
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P m68hc11_class_likely_spilled_p
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE m68hc11_option_override
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
-int
-m68hc11_override_options ()
+static void
+m68hc11_option_override (void)
 {
   memset (m68hc11_reg_valid_for_index, 0,
          sizeof (m68hc11_reg_valid_for_index));
@@ -253,21 +313,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_MIN_MAX);
+      target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
       m68hc11_cost = &m6811_cost;
       m68hc11_min_offset = 0;
       m68hc11_max_offset = 256;
@@ -278,8 +337,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.  */
@@ -297,31 +358,29 @@ 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";
+      if (m68hc11_soft_reg_count < 0)
+       m68hc11_soft_reg_count = 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;
@@ -339,47 +398,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);
-  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);
@@ -399,8 +455,7 @@ hard_regno_mode_ok (regno, mode)
 }
 
 int
-m68hc11_hard_regno_rename_ok (reg1, reg2)
-     int reg1, reg2;
+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.  */
@@ -416,9 +471,7 @@ m68hc11_hard_regno_rename_ok (reg1, reg2)
 }
 
 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;
 
@@ -426,97 +479,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);
        }
@@ -524,33 +577,63 @@ 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;
+}
+
+/* Implement TARGET_CLASS_LIKELY_SPILLED_P.  */
+
+static bool
+m68hc11_class_likely_spilled_p (reg_class_t rclass)
+{
+  switch (rclass)
+    {
+    case D_REGS:
+    case X_REGS:
+    case Y_REGS:
+    case A_REGS:
+    case SP_REGS:
+    case D_OR_X_REGS:
+    case D_OR_Y_REGS:
+    case X_OR_SP_REGS:
+    case Y_OR_SP_REGS:
+    case D_OR_SP_REGS:
+      return true;
+
+    default:
+      break;
+    }
+
+  return false;
 }
 
 /* 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:
@@ -562,36 +645,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;
@@ -601,18 +705,17 @@ 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
       && reg_equiv_memory_loc[REGNO (operand)])
     {
       operand = reg_equiv_memory_loc[REGNO (operand)];
-      operand = eliminate_regs (operand, 0, NULL_RTX);
+      operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
     }
 
   if (GET_CODE (operand) != MEM)
@@ -625,7 +728,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
@@ -664,24 +768,31 @@ 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, VOIDmode, 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;
+static bool
+m68hc11_legitimate_address_p_1  (enum machine_mode mode, rtx operand,
+                                 bool strict)
 {
+  int addr_mode;
+
   if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
     {
       /* Reject the global variables if they are too wide.  This forces
@@ -691,7 +802,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;
     }
@@ -706,11 +818,9 @@ go_if_legitimate_address_internal (operand, mode, strict)
   return 0;
 }
 
-int
-m68hc11_go_if_legitimate_address (operand, mode, strict)
-     rtx operand;
-     enum machine_mode mode;
-     int strict;
+bool
+m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
+                              bool strict)
 {
   int result;
 
@@ -721,7 +831,7 @@ m68hc11_go_if_legitimate_address (operand, mode, strict)
       debug_rtx (operand);
     }
 
-  result = go_if_legitimate_address_internal (operand, mode, strict);
+  result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
 
   if (debug_m6811)
     {
@@ -741,19 +851,9 @@ m68hc11_go_if_legitimate_address (operand, mode, strict)
   return result;
 }
 
-int
-m68hc11_legitimize_address (operand, old_operand, mode)
-     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;
 
@@ -776,9 +876,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:
        
@@ -826,19 +926,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;
        }
     }
@@ -848,13 +948,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;
@@ -868,7 +964,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:
@@ -876,11 +972,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 ();
@@ -891,9 +987,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
@@ -904,9 +999,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
@@ -917,74 +1010,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)
     {
@@ -997,88 +1023,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_MODE (operand) != mode && mode != VOIDmode)
-    return 0;
-
-  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_MODE (operand) != mode && mode != VOIDmode)
-    return 0;
-
-  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;
-{
-  if (GET_MODE (operand) != mode && mode != VOIDmode)
-    return 0;
-
-  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;
@@ -1097,8 +1066,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)
     {
@@ -1112,9 +1080,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))
     {
@@ -1140,63 +1106,6 @@ symbolic_memory_operand (op, mode)
       return 0;
     }
 }
-
-int
-m68hc11_eq_compare_operator (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == EQ || GET_CODE (op) == NE;
-}
-
-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;
-}
-
-/* Return true if op is a shift operator.  */
-int
-m68hc11_shift_operator (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
-    || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
-    || GET_CODE (op) == ASHIFTRT;
-}
-
-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.
    
@@ -1207,56 +1116,76 @@ m68hc11_unary_operator (op, mode)
    jmp FNADDR
 
 */
-void
-m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp;
-     rtx fnaddr;
-     rtx cxt;
+static void
+m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
 {
   const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx mem;
 
   /* Skip the '*'.  */
   if (*static_chain_reg == '*')
     static_chain_reg++;
   if (TARGET_M6811)
     {
-      emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
-      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
-      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
-                      GEN_INT (0x18df));
-      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
+      mem = adjust_address (m_tramp, HImode, 0);
+      emit_move_insn (mem, GEN_INT (0x18ce));
+      mem = adjust_address (m_tramp, HImode, 2);
+      emit_move_insn (mem, cxt);
+      mem = adjust_address (m_tramp, HImode, 4);
+      emit_move_insn (mem, GEN_INT (0x18df));
+      mem = adjust_address (m_tramp, QImode, 6);
+      emit_move_insn (mem,
                       gen_rtx_CONST (QImode,
                                      gen_rtx_SYMBOL_REF (Pmode,
                                                          static_chain_reg)));
-      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
-                      GEN_INT (0x7e));
-      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
+      mem = adjust_address (m_tramp, QImode, 7);
+      emit_move_insn (mem, GEN_INT (0x7e));
+      mem = adjust_address (m_tramp, HImode, 8);
+      emit_move_insn (mem, fnaddr);
     }
   else
     {
-      emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
-      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
-      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
+      mem = adjust_address (m_tramp, HImode, 0);
+      emit_move_insn (mem, GEN_INT (0x1803));
+      mem = adjust_address (m_tramp, HImode, 2);
+      emit_move_insn (mem, cxt);
+      mem = adjust_address (m_tramp, HImode, 4);
+      emit_move_insn (mem,
                       gen_rtx_CONST (HImode,
                                      gen_rtx_SYMBOL_REF (Pmode,
                                                          static_chain_reg)));
-      emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
-                      GEN_INT (0x06));
-      emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
+      mem = adjust_address (m_tramp, QImode, 6);
+      emit_move_insn (mem, GEN_INT (0x06));
+      mem = adjust_address (m_tramp, HImode, 7);
+      emit_move_insn (mem, fnaddr);
     }
 }
 \f
 /* Declaration of types.  */
 
-const struct attribute_spec m68hc11_attribute_table[] =
+/* 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)
 {
-  /* { 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 },
-  { NULL,        0, 0, false, false, false, NULL }
-};
+  tree decl = *node;
+
+  if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
+    {
+      DECL_SECTION_NAME (decl) = build_string (6, ".page0");
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored",
+              name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
 
 /* 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
@@ -1266,40 +1195,87 @@ 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",
-              IDENTIFIER_POINTER (name));
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+              name);
       *no_add_attrs = true;
     }
 
   return NULL_TREE;
 }
+/* Undo the effects of the above.  */
+
+static const char *
+m68hc11_strip_name_encoding (const char *str)
+{
+  return str + (*str == '*' || *str == '@' || *str == '&');
+}
+
+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 (decl, rtl, first)
-     tree decl;
-     rtx rtl;
-     int first ATTRIBUTE_UNUSED;
+m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
 {
   tree func_attr;
   int trap_handler;
   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;
 
@@ -1314,22 +1290,35 @@ m68hc11_encode_section_info (decl, rtl, first)
   trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
   if (trap_handler && is_far)
     {
-      warning ("`trap' and `far' attributes are not compatible, ignoring `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 ("`trap' attribute is already used");
+        warning (OPT_Wattributes, "%<trap%> attribute is already used");
       else
         trap_handler_symbol = XEXP (rtl, 0);
     }
   SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
 }
 
+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 (sym)
-     rtx sym;
+m68hc11_is_far_symbol (rtx sym)
 {
   if (GET_CODE (sym) == MEM)
     sym = XEXP (sym, 0);
@@ -1338,8 +1327,7 @@ m68hc11_is_far_symbol (sym)
 }
 
 int
-m68hc11_is_trap_symbol (sym)
-     rtx sym;
+m68hc11_is_trap_symbol (rtx sym)
 {
   if (GET_CODE (sym) == MEM)
     sym = XEXP (sym, 0);
@@ -1350,31 +1338,23 @@ m68hc11_is_trap_symbol (sym)
 
 /* Argument support functions.  */
 
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
-   Arrays are passed by references and other types by value.
+/* Given FROM and TO register numbers, say whether this elimination is
+   allowed. Frame pointer elimination is automatically handled.
 
-   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;
+   All other eliminations are valid.  */
+
+bool
+m68hc11_can_eliminate (const int from, const int to)
 {
-  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))) */ );
+  return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
+          ? ! frame_pointer_needed
+          : true);
 }
 
-
 /* 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;
@@ -1384,15 +1364,19 @@ 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_far = (TARGET_LONG_CALLS != 0
+                            && !current_function_interrupt
+                            && !trap_handler);
 
-  trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
   if (trap_handler && from == ARG_POINTER_REGNUM)
     size = 7;
 
@@ -1418,7 +1402,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;
        }
@@ -1441,10 +1425,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;
 
@@ -1485,7 +1466,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;
@@ -1497,11 +1478,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)
     {
@@ -1538,11 +1516,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)
     {
@@ -1552,13 +1527,13 @@ 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;
 }
@@ -1569,22 +1544,14 @@ m68hc11_function_arg (cum, mode, type, named)
    `downward' to pad below, or `none' to inhibit padding.
 
    Structures are stored left shifted in their argument slot.  */
-int
-m68hc11_function_arg_padding (mode, type)
-     enum machine_mode mode;
-     tree type;
+enum direction
+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
 
@@ -1593,8 +1560,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;
 
@@ -1611,32 +1577,20 @@ emit_move_after_reload (to, from, scratch)
   /* Put a REG_INC note to tell the flow analysis that the instruction
      is necessary.  */
   if (IS_STACK_PUSH (to))
-    {
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
-                                           XEXP (XEXP (to, 0), 0),
-                                           REG_NOTES (insn));
-    }
+    add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
   else if (IS_STACK_POP (from))
-    {
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
-                                           XEXP (XEXP (from, 0), 0),
-                                           REG_NOTES (insn));
-    }
+    add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
 
   /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
      to think that sp == _.frame and later replace a x = sp with x = _.frame.
      The problem is that we are lying to gcc and use `txs' for x = sp
      (which is not really true because txs is really x = sp + 1).  */
   else if (TARGET_M6811 && SP_REG_P (from))
-    {
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
-                                           from,
-                                           REG_NOTES (insn));
-    }
+    add_reg_note (insn, REG_INC, from);
 }
 
 int
-m68hc11_total_frame_size ()
+m68hc11_total_frame_size (void)
 {
   int size;
   int regno;
@@ -1650,16 +1604,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.  */
@@ -1667,15 +1620,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 ();
 
@@ -1691,13 +1643,15 @@ expand_prologue ()
   else if (lookup_attribute ("near", func_attr) != NULL_TREE)
     current_function_far = 0;
   else
-    current_function_far = TARGET_LONG_CALLS != 0;
+    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;
@@ -1714,9 +1668,9 @@ 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);
     }
 
@@ -1751,7 +1705,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.  */
@@ -1762,36 +1716,35 @@ 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 && return_size <= 2 * HARD_REG_SIZE)
     scratch = iy_reg;
@@ -1801,9 +1754,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);
        }
     }
@@ -1837,15 +1790,15 @@ 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));
     }
 
   /* 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);
     }
@@ -1866,12 +1819,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);
     }
 
@@ -1884,16 +1837,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
@@ -1929,26 +1880,33 @@ m68hc11_gen_lowpart (mode, x)
        {
          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_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);
 
@@ -1961,16 +1919,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
@@ -2007,12 +1963,16 @@ m68hc11_gen_highpart (mode, x)
          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_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)
     {
@@ -2026,9 +1986,13 @@ m68hc11_gen_highpart (mode, x)
        {
          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
@@ -2041,26 +2005,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
@@ -2069,8 +2029,10 @@ m68hc11_gen_highpart (mode, x)
       if (GET_CODE (x) == MEM)
        x = copy_rtx (x);
       return x;
+
+    default:
+      gcc_unreachable ();
     }
-  abort ();
 }
 \f
 
@@ -2082,20 +2044,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;
 
@@ -2162,9 +2122,7 @@ 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];
 
@@ -2206,11 +2164,8 @@ asm_print_register (file, regno)
    'T' generate the low-part temporary scratch register.  The operand is
        ignored.  */
 
-void
-print_operand (file, op, letter)
-     FILE *file;
-     rtx op;
-     int letter;
+static void
+m68hc11_print_operand (FILE *file, rtx op, int letter)
 {
   if (letter == 't')
     {
@@ -2278,48 +2233,42 @@ print_operand (file, op, letter)
       switch (GET_CODE (base))
        {
        case PRE_DEC:
-         if (TARGET_M6812)
-           {
-             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)
-           {
-             fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             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)
-           {
-             fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             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)
-           {
-             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, "[");
+         m68hc11_print_operand_address (file, XEXP (base, 0));
+         fprintf (file, "]");
+          break;
+
        default:
+          if (m68hc11_page0_symbol_p (base))
+            fprintf (file, "*");
+
          output_address (base);
          break;
        }
@@ -2333,8 +2282,7 @@ 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)
     {
       char dstr[30];
 
@@ -2361,11 +2309,10 @@ print_operand (file, op, letter)
 }
 
 /* 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;
 
@@ -2410,10 +2357,8 @@ must_parenthesize (op)
    assembler syntax for an instruction operand that is a memory
    reference whose address is ADDR.  ADDR is an RTL expression.  */
 
-void
-print_operand_address (file, addr)
-     FILE *file;
-     rtx addr;
+static void
+m68hc11_print_operand_address (FILE *file, rtx addr)
 {
   rtx base;
   rtx offset;
@@ -2422,8 +2367,7 @@ 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));
 
       fprintf (file, "0,");
       asm_print_register (file, REGNO (addr));
@@ -2434,45 +2378,29 @@ print_operand_address (file, addr)
       switch (GET_CODE (base))
        {
        case PRE_DEC:
-         if (TARGET_M6812)
-           {
-             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)
-           {
-             fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             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)
-           {
-             fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
-             asm_print_register (file, REGNO (XEXP (base, 0)));
-             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)
-           {
-             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:
@@ -2495,10 +2423,11 @@ 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)
            fprintf (file, "(");
 
@@ -2508,18 +2437,15 @@ print_operand_address (file, addr)
          if (need_parenthesis)
            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));
-                 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
            {
@@ -2534,10 +2460,6 @@ print_operand_address (file, addr)
              asm_print_register (file, REGNO (base));
            }
        }
-      else
-       {
-         abort ();
-       }
       break;
 
     default:
@@ -2564,28 +2486,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;
 
@@ -2698,15 +2613,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 ();
          }
 
        /*
@@ -2716,20 +2631,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;
 }
@@ -2737,8 +2652,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;
@@ -2754,9 +2668,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;
   
@@ -2780,8 +2692,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;
@@ -2897,7 +2808,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)
         {
@@ -2915,15 +2826,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)
     {
@@ -2987,11 +2890,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;
@@ -3031,10 +2930,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, enum rtx_code code, rtx *operands)
 {
   rtx result;
   int need_copy;
@@ -3065,18 +2961,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])));
        }
     }
 
@@ -3103,10 +3000,8 @@ 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, enum rtx_code code,
+                      rtx *operands)
 {
   rtx low[4];
   rtx high[4];
@@ -3116,26 +3011,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];
@@ -3154,9 +3031,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
@@ -3172,10 +3047,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
@@ -3191,10 +3066,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
@@ -3208,9 +3083,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;
 
@@ -3231,9 +3104,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;
 
@@ -3248,10 +3119,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:
@@ -3259,17 +3133,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:
@@ -3277,7 +3151,7 @@ m68hc11_gen_movhi (insn, operands)
              output_asm_insn ("pul%0", operands);
              break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
          return;
        }
@@ -3290,17 +3164,6 @@ m68hc11_gen_movhi (insn, operands)
        {
          if (SP_REG_P (operands[0]))
            output_asm_insn ("lds\t%1", operands);
-         else if (0 /* REG_WAS_0 note is boggus;  don't rely on it.  */
-                   && !D_REG_P (operands[0])
-                   && GET_CODE (operands[1]) == CONST_INT
-                   && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
-                   && find_reg_note (insn, REG_WAS_0, 0))
-            {
-              if (INTVAL (operands[1]) == 1)
-                output_asm_insn ("in%0", operands);
-              else
-                output_asm_insn ("de%0", operands);
-            }
          else
            output_asm_insn ("ld%0\t%1", operands);
        }
@@ -3311,11 +3174,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))
@@ -3332,6 +3236,7 @@ m68hc11_gen_movhi (insn, operands)
                  ops[0] = to;
                  ops[1] = operands[2];
                  m68hc11_gen_movhi (insn, ops);
+                  return;
                }
              else
                {
@@ -3339,19 +3244,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;
     }
@@ -3370,7 +3267,7 @@ m68hc11_gen_movhi (insn, operands)
          output_asm_insn ("pulb", operands);
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     }
@@ -3484,16 +3381,6 @@ m68hc11_gen_movhi (insn, operands)
              cc_status = cc_prev_status;
              output_asm_insn ("tsx", operands);
            }
-         else if (0 /* REG_WAS_0 note is boggus;  don't rely on it.  */
-                   && GET_CODE (operands[1]) == CONST_INT
-                   && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
-                   && find_reg_note (insn, REG_WAS_0, 0))
-            {
-              if (INTVAL (operands[1]) == 1)
-                output_asm_insn ("in%0", operands);
-              else
-                output_asm_insn ("de%0", operands);
-            }
          else
            {
              output_asm_insn ("ldx\t%1", operands);
@@ -3542,16 +3429,6 @@ m68hc11_gen_movhi (insn, operands)
              cc_status = cc_prev_status;
              output_asm_insn ("tsy", operands);
            }
-         else if (0 /* REG_WAS_0 note is boggus;  don't rely on it.  */
-                   && GET_CODE (operands[1]) == CONST_INT
-                   && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
-                   && find_reg_note (insn, REG_WAS_0, 0))
-            {
-              if (INTVAL (operands[1]) == 1)
-                output_asm_insn ("in%0", operands);
-              else
-                output_asm_insn ("de%0", operands);
-            }
           else
            {
              output_asm_insn ("ldy\t%1", operands);
@@ -3614,7 +3491,7 @@ m68hc11_gen_movhi (insn, operands)
          output_asm_insn ("psha", operands);
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     }
@@ -3678,9 +3555,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
@@ -3701,8 +3576,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
@@ -3792,16 +3669,6 @@ m68hc11_gen_movqi (insn, operands)
                  output_asm_insn ("ldab\t%T0", operands);
                }
            }
-         else if (0 /* REG_WAS_0 note is boggus;  don't rely on it.  */
-                   && GET_CODE (operands[1]) == CONST_INT
-                   && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
-                   && find_reg_note (insn, REG_WAS_0, 0))
-            {
-              if (INTVAL (operands[1]) == 1)
-                output_asm_insn ("inc%b0", operands);
-              else
-                output_asm_insn ("dec%b0", operands);
-            }          
          else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
                   && !DA_REG_P (operands[1]))
            {
@@ -3970,10 +3837,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;
   
@@ -4052,9 +3916,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)
@@ -4078,7 +3940,11 @@ m68hc11_notice_update_cc (exp, insn)
        {
          cc_status.flags = 0;
          cc_status.value1 = XEXP (exp, 0);
-         cc_status.value2 = XEXP (exp, 1);
+         if (GET_CODE (XEXP (exp, 1)) == COMPARE
+             && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
+           cc_status.value2 = XEXP (XEXP (exp, 1), 0);
+         else
+           cc_status.value2 = XEXP (exp, 1);
        }
       else
        {
@@ -4148,14 +4014,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
@@ -4230,10 +4101,10 @@ struct replace_info
   int z_loaded_with_sp;
 };
 
-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;
 
@@ -4243,9 +4114,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;
@@ -4318,8 +4187,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)
                {
@@ -4435,9 +4306,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;
                }
@@ -4518,9 +4387,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;
                }
@@ -4808,9 +4675,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;
 
@@ -4885,7 +4750,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)
     {
@@ -4917,12 +4782,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;
@@ -4938,26 +4802,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;
@@ -4975,19 +4839,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);
     }
 
@@ -5047,7 +4911,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);
            }
 
@@ -5079,8 +4943,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);
     }
 
@@ -5089,12 +4953,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;
 
@@ -5114,13 +4978,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);
     }
 
@@ -5132,15 +4996,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.  */
@@ -5153,7 +5016,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);
@@ -5197,20 +5060,20 @@ m68hc11_reassign_regs (first)
    'z_replacement_completed' is set to 2.  */
 
 static void
-m68hc11_reorg ()
+m68hc11_reorg (void)
 {
   int split_done = 0;
-  rtx insn, first;
+  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;
@@ -5221,7 +5084,7 @@ m68hc11_reorg ()
   if (optimize)
     compute_bb_for_insn ();
 
-  /* After some splitting, there are some oportunities for CSE pass.
+  /* 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)
     {
@@ -5232,29 +5095,9 @@ m68hc11_reorg ()
      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);
-                }
-            }
-        }
-
-      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;
@@ -5282,7 +5125,7 @@ m68hc11_reorg ()
 
        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.  */
@@ -5290,26 +5133,33 @@ m68hc11_reorg ()
        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);
@@ -5331,10 +5181,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.  */
@@ -5356,8 +5204,7 @@ m68hc11_register_move_cost (mode, from, to)
    If ADDR is not a valid address, its cost is irrelevant.  */
 
 static int
-m68hc11_address_cost (addr)
-     rtx addr;
+m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
 {
   int cost = 4;
 
@@ -5438,14 +5285,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)
@@ -5470,10 +5314,8 @@ m68hc11_shift_cost (mode, x, shift)
 }
 
 static int
-m68hc11_rtx_costs_1 (x, code, outer_code)
-     rtx x;
-     enum rtx_code code;
-     enum rtx_code outer_code ATTRIBUTE_UNUSED;
+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;
@@ -5491,14 +5333,14 @@ m68hc11_rtx_costs_1 (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.  */
@@ -5507,7 +5349,7 @@ m68hc11_rtx_costs_1 (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)
        {
@@ -5518,7 +5360,7 @@ m68hc11_rtx_costs_1 (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:
@@ -5541,18 +5383,19 @@ m68hc11_rtx_costs_1 (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:
@@ -5579,7 +5422,8 @@ m68hc11_rtx_costs_1 (x, code, outer_code)
     case COMPARE:
     case ABS:
     case ZERO_EXTEND:
-      total = extra_cost + rtx_cost (XEXP (x, 0), code);
+    case ZERO_EXTRACT:
+      total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
       if (mode == QImode)
        {
          return total + COSTS_N_INSNS (1);
@@ -5606,11 +5450,12 @@ m68hc11_rtx_costs_1 (x, code, outer_code)
 }
 
 static bool
-m68hc11_rtx_costs (x, code, outer_code, total)
-     rtx x;
-     int code, outer_code;
-     int *total;
+m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
+                  bool speed ATTRIBUTE_UNUSED)
 {
+  enum rtx_code code = (enum rtx_code) codearg;
+  enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
+
   switch (code)
     {
       /* Constants are cheap.  Moving them in registers must be avoided
@@ -5631,8 +5476,9 @@ m68hc11_rtx_costs (x, code, outer_code, total)
        *total = 0;
       return true;
     
-       if (outer_code == SET)
-        *total = 1 - reload_completed;
+    case ZERO_EXTRACT:
+      if (outer_code != COMPARE)
+       return false;
 
     case ROTATE:
     case ROTATERT:
@@ -5663,83 +5509,58 @@ m68hc11_rtx_costs (x, code, outer_code, total)
 }
 \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>
+/* Worker function for TARGET_ASM_FILE_START.  */
 
 static void
-print_options (out)
-     FILE *out;
+m68hc11_file_start (void)
 {
-  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
+  default_file_start ();
+  
+  fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
 }
 
-void
-m68hc11_asm_file_start (out, main_file)
-     FILE *out;
-     const char *main_file;
-{
-  fprintf (out, ";;;-----------------------------------------\n");
-  fprintf (out, ";;; Start %s gcc assembly output\n",
-           TARGET_M6811
-           ? "MC68HC11"
-           : TARGET_M68S12 ? "MC68HCS12" : "MC68HC12");
-  fprintf (out, ";;; gcc compiler %s\n", version_string);
-  print_options (out);
-  fprintf (out, ";;;-----------------------------------------\n");
-  output_file_directive (out, main_file);
-
-  if (TARGET_SHORT)
-    fprintf (out, "\t.mode mshort\n");
-  else
-    fprintf (out, "\t.mode mlong\n");
-}
 
+/* 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"