]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/m68k/m68k.c
2012-10-23 Vladimir Makarov <vmakarov@redhat.com>
[thirdparty/gcc.git] / gcc / config / m68k / m68k.c
index c5a668a497b6fe4df6b347ae413c0c12732c0b58..e86960efc7b22c4be67ab316cd19dc37f27817d1 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines for insn-output.c for Motorola 68000 family.
    Copyright (C) 1987, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -28,13 +28,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "function.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "recog.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "expr.h"
 #include "reload.h"
 #include "tm_p.h"
@@ -47,6 +46,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "sched-int.h"
 #include "insn-codes.h"
 #include "ggc.h"
+#include "opts.h"
+#include "optabs.h"
 
 enum reg_class regno_reg_class[] =
 {
@@ -132,8 +133,11 @@ static void m68k_sched_dfa_pre_advance_cycle (void);
 static void m68k_sched_dfa_post_advance_cycle (void);
 static int m68k_sched_first_cycle_multipass_dfa_lookahead (void);
 
+static bool m68k_can_eliminate (const int, const int);
+static void m68k_conditional_register_usage (void);
 static bool m68k_legitimate_address_p (enum machine_mode, rtx, bool);
-static bool m68k_handle_option (size_t, const char *, int);
+static void m68k_option_override (void);
+static void m68k_override_options_after_change (void);
 static rtx find_addr_reg (rtx);
 static const char *singlemove_string (rtx *);
 static void m68k_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
@@ -147,15 +151,21 @@ static bool m68k_save_reg (unsigned int regno, bool interrupt_handler);
 static bool m68k_ok_for_sibcall_p (tree, tree);
 static bool m68k_tls_symbol_p (rtx);
 static rtx m68k_legitimize_address (rtx, rtx, enum machine_mode);
-static bool m68k_rtx_costs (rtx, int, int, int *, bool);
+static bool m68k_rtx_costs (rtx, int, int, int, int *, bool);
 #if M68K_HONOR_TARGET_STRICT_ALIGNMENT
 static bool m68k_return_in_memory (const_tree, const_tree);
 #endif
 static void m68k_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
-\f
-
-/* Specify the identification number of the library being built */
-const char *m68k_library_id_string = "_current_shared_library_a5_offset_";
+static void m68k_trampoline_init (rtx, tree, rtx);
+static int m68k_return_pops_args (tree, tree, int);
+static rtx m68k_delegitimize_address (rtx);
+static void m68k_function_arg_advance (cumulative_args_t, enum machine_mode,
+                                      const_tree, bool);
+static rtx m68k_function_arg (cumulative_args_t, enum machine_mode,
+                             const_tree, bool);
+static bool m68k_cannot_force_const_mem (enum machine_mode mode, rtx x);
+static bool m68k_output_addr_const_extra (FILE *, rtx);
+static void m68k_init_sync_libfuncs (void) ATTRIBUTE_UNUSED;
 \f
 /* Initialize the GCC target structure.  */
 
@@ -226,8 +236,11 @@ const char *m68k_library_id_string = "_current_shared_library_a5_offset_";
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD       \
   m68k_sched_first_cycle_multipass_dfa_lookahead
 
-#undef TARGET_HANDLE_OPTION
-#define TARGET_HANDLE_OPTION m68k_handle_option
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE m68k_option_override
+
+#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE
+#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE m68k_override_options_after_change
 
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS m68k_rtx_costs
@@ -242,7 +255,7 @@ const char *m68k_library_id_string = "_current_shared_library_a5_offset_";
 #define TARGET_STRUCT_VALUE_RTX m68k_struct_value_rtx
 
 #undef TARGET_CANNOT_FORCE_CONST_MEM
-#define TARGET_CANNOT_FORCE_CONST_MEM m68k_illegitimate_symbolic_constant_p
+#define TARGET_CANNOT_FORCE_CONST_MEM m68k_cannot_force_const_mem
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL m68k_ok_for_sibcall_p
@@ -263,13 +276,48 @@ const char *m68k_library_id_string = "_current_shared_library_a5_offset_";
 #undef TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P    m68k_legitimate_address_p
 
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE m68k_can_eliminate
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE m68k_conditional_register_usage
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT m68k_trampoline_init
+
+#undef TARGET_RETURN_POPS_ARGS
+#define TARGET_RETURN_POPS_ARGS m68k_return_pops_args
+
+#undef TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS m68k_delegitimize_address
+
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG m68k_function_arg
+
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE m68k_function_arg_advance
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P m68k_legitimate_constant_p
+
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA m68k_output_addr_const_extra
+
+/* The value stored by TAS.  */
+#undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+#define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 128
+
 static const struct attribute_spec m68k_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "interrupt", 0, 0, true,  false, false, m68k_handle_fndecl_attribute },
-  { "interrupt_handler", 0, 0, true,  false, false, m68k_handle_fndecl_attribute },
-  { "interrupt_thread", 0, 0, true,  false, false, m68k_handle_fndecl_attribute },
-  { NULL,                0, 0, false, false, false, NULL }
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity } */
+  { "interrupt", 0, 0, true,  false, false, m68k_handle_fndecl_attribute,
+    false },
+  { "interrupt_handler", 0, 0, true,  false, false,
+    m68k_handle_fndecl_attribute, false },
+  { "interrupt_thread", 0, 0, true,  false, false,
+    m68k_handle_fndecl_attribute, false },
+  { NULL,                0, 0, false, false, false, NULL, false }
 };
 
 struct gcc_target targetm = TARGET_INITIALIZER;
@@ -281,7 +329,7 @@ struct gcc_target targetm = TARGET_INITIALIZER;
    generated 68881 code for 68020 and 68030 targets unless explicitly told
    not to.  */
 #define FL_FOR_isa_20    (FL_FOR_isa_10 | FL_ISA_68020 \
-                         | FL_BITFIELD | FL_68881)
+                         | FL_BITFIELD | FL_68881 | FL_CAS)
 #define FL_FOR_isa_40    (FL_FOR_isa_20 | FL_ISA_68040)
 #define FL_FOR_isa_cpu32 (FL_FOR_isa_10 | FL_ISA_68020)
 
@@ -342,20 +390,10 @@ static const struct m68k_target_selection all_devices[] =
    Used for -march selection.  */
 static const struct m68k_target_selection all_isas[] =
 {
-  { "68000",    m68000,     NULL,  u68000,   isa_00,    FL_FOR_isa_00 },
-  { "68010",    m68010,     NULL,  u68010,   isa_10,    FL_FOR_isa_10 },
-  { "68020",    m68020,     NULL,  u68020,   isa_20,    FL_FOR_isa_20 },
-  { "68030",    m68030,     NULL,  u68030,   isa_20,    FL_FOR_isa_20 },
-  { "68040",    m68040,     NULL,  u68040,   isa_40,    FL_FOR_isa_40 },
-  { "68060",    m68060,     NULL,  u68060,   isa_40,    FL_FOR_isa_40 },
-  { "cpu32",    cpu32,      NULL,  ucpu32,   isa_20,    FL_FOR_isa_cpu32 },
-  { "isaa",     mcf5206e,   NULL,  ucfv2,    isa_a,     (FL_FOR_isa_a
-                                                        | FL_CF_HWDIV) },
-  { "isaaplus", mcf5271,    NULL,  ucfv2,    isa_aplus, (FL_FOR_isa_aplus
-                                                        | FL_CF_HWDIV) },
-  { "isab",     mcf5407,    NULL,  ucfv4,    isa_b,     FL_FOR_isa_b },
-  { "isac",     unk_device, NULL,  ucfv4,    isa_c,     (FL_FOR_isa_c
-                                                        | FL_CF_HWDIV) },
+#define M68K_ISA(NAME,DEVICE,MICROARCH,ISA,FLAGS) \
+  { NAME, DEVICE, NULL, u##MICROARCH, ISA, FLAGS },
+#include "m68k-isas.def"
+#undef M68K_ISA
   { NULL,       unk_device, NULL,  unk_arch, isa_max,   0 }
 };
 
@@ -363,24 +401,10 @@ static const struct m68k_target_selection all_isas[] =
    device.  Used for -mtune selection.  */
 static const struct m68k_target_selection all_microarchs[] =
 {
-  { "68000",    m68000,     NULL,  u68000,    isa_00,  FL_FOR_isa_00 },
-  { "68010",    m68010,     NULL,  u68010,    isa_10,  FL_FOR_isa_10 },
-  { "68020",    m68020,     NULL,  u68020,    isa_20,  FL_FOR_isa_20 },
-  { "68020-40", m68020,     NULL,  u68020_40, isa_20,  FL_FOR_isa_20 },
-  { "68020-60", m68020,     NULL,  u68020_60, isa_20,  FL_FOR_isa_20 },
-  { "68030",    m68030,     NULL,  u68030,    isa_20,  FL_FOR_isa_20 },
-  { "68040",    m68040,     NULL,  u68040,    isa_40,  FL_FOR_isa_40 },
-  { "68060",    m68060,     NULL,  u68060,    isa_40,  FL_FOR_isa_40 },
-  { "cpu32",    cpu32,      NULL,  ucpu32,    isa_20,  FL_FOR_isa_cpu32 },
-  { "cfv1",     mcf51qe,    NULL,  ucfv1,     isa_c,   FL_FOR_isa_c },
-  { "cfv2",     mcf5206,    NULL,  ucfv2,     isa_a,   FL_FOR_isa_a },
-  { "cfv3",     mcf5307,    NULL,  ucfv3,     isa_a,   (FL_FOR_isa_a
-                                                       | FL_CF_HWDIV) },
-  { "cfv4",     mcf5407,    NULL,  ucfv4,     isa_b,   FL_FOR_isa_b },
-  { "cfv4e",    mcf547x,    NULL,  ucfv4e,    isa_b,   (FL_FOR_isa_b
-                                                       | FL_CF_USP
-                                                       | FL_CF_EMAC
-                                                       | FL_CF_FPU) },
+#define M68K_MICROARCH(NAME,DEVICE,MICROARCH,ISA,FLAGS) \
+  { NAME, DEVICE, NULL, u##MICROARCH, ISA, FLAGS },
+#include "m68k-microarchs.def"
+#undef M68K_MICROARCH
   { NULL,       unk_device, NULL,  unk_arch,  isa_max, 0 }
 };
 \f
@@ -415,128 +439,22 @@ const char *m68k_symbolic_jump;
 enum M68K_SYMBOLIC_CALL m68k_symbolic_call_var;
 
 \f
-/* See whether TABLE has an entry with name NAME.  Return true and
-   store the entry in *ENTRY if so, otherwise return false and
-   leave *ENTRY alone.  */
-
-static bool
-m68k_find_selection (const struct m68k_target_selection **entry,
-                    const struct m68k_target_selection *table,
-                    const char *name)
-{
-  size_t i;
-
-  for (i = 0; table[i].name; i++)
-    if (strcmp (table[i].name, name) == 0)
-      {
-       *entry = table + i;
-       return true;
-      }
-  return false;
-}
-
-/* Implement TARGET_HANDLE_OPTION.  */
+/* Implement TARGET_OPTION_OVERRIDE.  */
 
-static bool
-m68k_handle_option (size_t code, const char *arg, int value)
+static void
+m68k_option_override (void)
 {
-  switch (code)
-    {
-    case OPT_march_:
-      return m68k_find_selection (&m68k_arch_entry, all_isas, arg);
-
-    case OPT_mcpu_:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, arg);
-
-    case OPT_mtune_:
-      return m68k_find_selection (&m68k_tune_entry, all_microarchs, arg);
-
-    case OPT_m5200:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "5206");
-
-    case OPT_m5206e:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "5206e");
-
-    case OPT_m528x:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "528x");
-
-    case OPT_m5307:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "5307");
-
-    case OPT_m5407:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "5407");
-
-    case OPT_mcfv4e:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "547x");
-
-    case OPT_m68000:
-    case OPT_mc68000:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68000");
-
-    case OPT_m68010:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68010");
-
-    case OPT_m68020:
-    case OPT_mc68020:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68020");
-
-    case OPT_m68020_40:
-      return (m68k_find_selection (&m68k_tune_entry, all_microarchs,
-                                  "68020-40")
-             && m68k_find_selection (&m68k_cpu_entry, all_devices, "68020"));
-
-    case OPT_m68020_60:
-      return (m68k_find_selection (&m68k_tune_entry, all_microarchs,
-                                  "68020-60")
-             && m68k_find_selection (&m68k_cpu_entry, all_devices, "68020"));
-
-    case OPT_m68030:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68030");
-
-    case OPT_m68040:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68040");
-
-    case OPT_m68060:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68060");
-
-    case OPT_m68302:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68302");
-
-    case OPT_m68332:
-    case OPT_mcpu32:
-      return m68k_find_selection (&m68k_cpu_entry, all_devices, "68332");
-
-    case OPT_mshared_library_id_:
-      if (value > MAX_LIBRARY_ID)
-       error ("-mshared-library-id=%s is not between 0 and %d",
-              arg, MAX_LIBRARY_ID);
-      else
-        {
-         char *tmp;
-         asprintf (&tmp, "%d", (value * -4) - 4);
-         m68k_library_id_string = tmp;
-       }
-      return true;
-
-    default:
-      return true;
-    }
-}
+  const struct m68k_target_selection *entry;
+  unsigned long target_mask;
 
-/* Sometimes certain combinations of command options do not make
-   sense on a particular target machine.  You can define a macro
-   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
-   defined, is executed once just after all the command options have
-   been parsed.
+  if (global_options_set.x_m68k_arch_option)
+    m68k_arch_entry = &all_isas[m68k_arch_option];
 
-   Don't use this macro to turn on various extra optimizations for
-   `-O'.  That is what `OPTIMIZATION_OPTIONS' is for.  */
+  if (global_options_set.x_m68k_cpu_option)
+    m68k_cpu_entry = &all_devices[(int) m68k_cpu_option];
 
-void
-override_options (void)
-{
-  const struct m68k_target_selection *entry;
-  unsigned long target_mask;
+  if (global_options_set.x_m68k_tune_option)
+    m68k_tune_entry = &all_microarchs[(int) m68k_tune_option];
 
   /* User can choose:
 
@@ -700,6 +618,12 @@ override_options (void)
     }
 #endif
 
+  if (stack_limit_rtx != NULL_RTX && !TARGET_68020)
+    {
+      warning (0, "-fstack-limit- options are not supported on this cpu");
+      stack_limit_rtx = NULL_RTX;
+    }
+
   SUBTARGET_OVERRIDE_OPTIONS;
 
   /* Setup scheduling options.  */
@@ -730,6 +654,19 @@ override_options (void)
     }
 }
 
+/* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE.  */
+
+static void
+m68k_override_options_after_change (void)
+{
+  if (m68k_sched_cpu == CPU_UNKNOWN)
+    {
+      flag_schedule_insns = 0;
+      flag_schedule_insns_after_reload = 0;
+      flag_modulo_sched = 0;
+    }
+}
+
 /* Generate a macro of the form __mPREFIX_cpu_NAME, where PREFIX is the
    given argument and NAME is the argument passed to -mcpu.  Return NULL
    if -mcpu was not passed.  */
@@ -866,6 +803,14 @@ m68k_compute_frame_layout (void)
   current_frame.funcdef_no = current_function_funcdef_no;
 }
 
+/* Worker function for TARGET_CAN_ELIMINATE.  */
+
+bool
+m68k_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+  return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true);
+}
+
 HOST_WIDE_INT
 m68k_initial_elimination_offset (int from, int to)
 {
@@ -943,7 +888,7 @@ m68k_save_reg (unsigned int regno, bool interrupt_handler)
       if (df_regs_ever_live_p (regno))
        return true;
 
-      if (!current_function_is_leaf && call_used_regs[regno])
+      if (!crtl->is_leaf && call_used_regs[regno])
        return true;
     }
 
@@ -977,16 +922,17 @@ m68k_emit_movem (rtx base, HOST_WIDE_INT offset,
 
   if (adjust_stack_p)
     {
-      src = plus_constant (base, (count
-                                 * GET_MODE_SIZE (mode)
-                                 * (HOST_WIDE_INT) (store_p ? -1 : 1)));
+      src = plus_constant (Pmode, base,
+                          (count
+                           * GET_MODE_SIZE (mode)
+                           * (HOST_WIDE_INT) (store_p ? -1 : 1)));
       XVECEXP (body, 0, i++) = gen_rtx_SET (VOIDmode, base, src);
     }
 
   for (; mask != 0; mask >>= 1, regno++)
     if (mask & 1)
       {
-       addr = plus_constant (base, offset);
+       addr = plus_constant (Pmode, base, offset);
        operands[!store_p] = gen_frame_mem (mode, addr);
        operands[store_p] = gen_rtx_REG (mode, regno);
        XVECEXP (body, 0, i++)
@@ -1019,17 +965,21 @@ void
 m68k_expand_prologue (void)
 {
   HOST_WIDE_INT fsize_with_regs;
-  rtx limit, src, dest, insn;
+  rtx limit, src, dest;
 
   m68k_compute_frame_layout ();
 
+  if (flag_stack_usage_info)
+    current_function_static_stack_size
+      = current_frame.size + current_frame.offset;
+
   /* If the stack limit is a symbol, we can check it here,
      before actually allocating the space.  */
   if (crtl->limit_stack
       && GET_CODE (stack_limit_rtx) == SYMBOL_REF)
     {
-      limit = plus_constant (stack_limit_rtx, current_frame.size + 4);
-      if (!LEGITIMATE_CONSTANT_P (limit))
+      limit = plus_constant (Pmode, stack_limit_rtx, current_frame.size + 4);
+      if (!m68k_legitimate_constant_p (Pmode, limit))
        {
          emit_move_insn (gen_rtx_REG (Pmode, D0_REG), limit);
          limit = gen_rtx_REG (Pmode, D0_REG);
@@ -1162,7 +1112,7 @@ m68k_expand_prologue (void)
 
   if (!TARGET_SEP_DATA
       && crtl->uses_pic_offset_table)
-    insn = emit_insn (gen_load_got (pic_offset_table_rtx));
+    emit_insn (gen_load_got (pic_offset_table_rtx));
 }
 \f
 /* Return true if a simple (return) instruction is sufficient for this
@@ -1198,12 +1148,11 @@ m68k_expand_epilogue (bool sibcall_p)
   big = false;
   restore_from_sp = false;
 
-  /* FIXME : current_function_is_leaf below is too strong.
+  /* FIXME : crtl->is_leaf below is too strong.
      What we really need to know there is if there could be pending
      stack adjustment needed at that point.  */
   restore_from_sp = (!frame_pointer_needed
-                    || (!cfun->calls_alloca
-                        && current_function_is_leaf));
+                    || (!cfun->calls_alloca && crtl->is_leaf));
 
   /* fsize_with_regs is the size we need to adjust the sp when
      popping the frame.  */
@@ -1262,12 +1211,12 @@ m68k_expand_epilogue (bool sibcall_p)
                /* Generate the address -OFFSET(%fp,%a1.l).  */
                addr = gen_rtx_REG (Pmode, A1_REG);
                addr = gen_rtx_PLUS (Pmode, addr, frame_pointer_rtx);
-               addr = plus_constant (addr, -offset);
+               addr = plus_constant (Pmode, addr, -offset);
              }
            else if (restore_from_sp)
              addr = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
            else
-             addr = plus_constant (frame_pointer_rtx, -offset);
+             addr = plus_constant (Pmode, frame_pointer_rtx, -offset);
            emit_move_insn (gen_rtx_REG (SImode, D0_REG + i),
                            gen_frame_mem (SImode, addr));
            offset -= GET_MODE_SIZE (SImode);
@@ -1346,7 +1295,7 @@ m68k_expand_epilogue (bool sibcall_p)
                           EH_RETURN_STACKADJ_RTX));
 
   if (!sibcall_p)
-    emit_jump_insn (gen_rtx_RETURN (VOIDmode));
+    emit_jump_insn (ret_rtx);
 }
 \f
 /* Return true if X is a valid comparison operator for the dbcc 
@@ -1383,6 +1332,30 @@ flags_in_68881 (void)
   return cc_status.flags & CC_IN_68881;
 }
 
+/* Return true if PARALLEL contains register REGNO.  */
+static bool
+m68k_reg_present_p (const_rtx parallel, unsigned int regno)
+{
+  int i;
+
+  if (REG_P (parallel) && REGNO (parallel) == regno)
+    return true;
+
+  if (GET_CODE (parallel) != PARALLEL)
+    return false;
+
+  for (i = 0; i < XVECLEN (parallel, 0); ++i)
+    {
+      const_rtx x;
+
+      x = XEXP (XVECEXP (parallel, 0, i), 0);
+      if (REG_P (x) && REGNO (x) == regno)
+       return true;
+    }
+
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL_P.  */
 
 static bool
@@ -1395,6 +1368,26 @@ m68k_ok_for_sibcall_p (tree decl, tree exp)
   if (CALL_EXPR_STATIC_CHAIN (exp))
     return false;
 
+  if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl))))
+    {
+      /* Check that the return value locations are the same.  For
+        example that we aren't returning a value from the sibling in
+        a D0 register but then need to transfer it to a A0 register.  */
+      rtx cfun_value;
+      rtx call_value;
+
+      cfun_value = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (cfun->decl)),
+                                  cfun->decl);
+      call_value = FUNCTION_VALUE (TREE_TYPE (exp), decl);
+
+      /* Check that the values are equal or that the result the callee
+        function returns is superset of what the current function returns.  */
+      if (!(rtx_equal_p (cfun_value, call_value)
+           || (REG_P (cfun_value)
+               && m68k_reg_present_p (call_value, REGNO (cfun_value)))))
+       return false;
+    }
+
   kind = m68k_get_function_kind (current_function_decl);
   if (kind == m68k_fk_normal_function)
     /* We can always sibcall from a normal function, because it's
@@ -1409,6 +1402,28 @@ m68k_ok_for_sibcall_p (tree decl, tree exp)
   return false;
 }
 
+/* On the m68k all args are always pushed.  */
+
+static rtx
+m68k_function_arg (cumulative_args_t cum ATTRIBUTE_UNUSED,
+                  enum machine_mode mode ATTRIBUTE_UNUSED,
+                  const_tree type ATTRIBUTE_UNUSED,
+                  bool named ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
+static void
+m68k_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+                          const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+
+  *cum += (mode != BLKmode
+          ? (GET_MODE_SIZE (mode) + 3) & ~3
+          : (int_size_in_bytes (type) + 3) & ~3);
+}
+
 /* Convert X to a legitimate function call memory reference and return the
    result.  */
 
@@ -1442,7 +1457,7 @@ m68k_legitimize_sibcall_address (rtx x)
    However, if REG is a broken-out memory address or multiplication,
    nothing needs to be done because REG can certainly go in an address reg.  */
 
-rtx
+static rtx
 m68k_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
 {
   if (m68k_tls_symbol_p (x))
@@ -1869,6 +1884,14 @@ m68k_illegitimate_symbolic_constant_p (rtx x)
   return m68k_tls_reference_p (x, false);
 }
 
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM.  */
+
+static bool
+m68k_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+  return m68k_illegitimate_symbolic_constant_p (x);
+}
+
 /* Return true if X is a legitimate constant address that can reach
    bytes in the range [X, X + REACH).  STRICT_P says whether we need
    strict checking.  */
@@ -2086,6 +2109,14 @@ m68k_legitimate_mem_p (rtx x, struct m68k_address *address)
                                     address));
 }
 
+/* Implement TARGET_LEGITIMATE_CONSTANT_P.  */
+
+bool
+m68k_legitimate_constant_p (enum machine_mode mode, rtx x)
+{
+  return mode != XFmode && !m68k_illegitimate_symbolic_constant_p (x);
+}
+
 /* Return true if X matches the 'Q' constraint.  It must be a memory
    with a base address and no constant offset or index.  */
 
@@ -2425,7 +2456,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
                                     base == reg ? 0 : reg);
 
       if (GET_CODE (orig) == CONST_INT)
-       pic_ref = plus_constant (base, INTVAL (orig));
+       pic_ref = plus_constant (Pmode, base, INTVAL (orig));
       else
        pic_ref = gen_rtx_PLUS (Pmode, base, orig);
     }
@@ -2750,8 +2781,8 @@ const_int_cost (HOST_WIDE_INT i)
 }
 
 static bool
-m68k_rtx_costs (rtx x, int code, int outer_code, int *total,
-               bool speed ATTRIBUTE_UNUSED)
+m68k_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
+               int *total, bool speed ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
@@ -3414,6 +3445,7 @@ handle_move_double (rtx operands[2],
 
   /* Normal case: do the two words, low-numbered first.  */
 
+  m68k_final_prescan_insn (NULL, operands, 2);
   handle_movsi (operands);
 
   /* Do the middle one of the three words for long double */
@@ -3424,6 +3456,7 @@ handle_move_double (rtx operands[2],
       if (addreg1)
        handle_reg_adjust (addreg1, 4);
 
+      m68k_final_prescan_insn (NULL, middlehalf, 2);
       handle_movsi (middlehalf);
     }
 
@@ -3434,6 +3467,7 @@ handle_move_double (rtx operands[2],
     handle_reg_adjust (addreg1, 4);
 
   /* Do that word.  */
+  m68k_final_prescan_insn (NULL, latehalf, 2);
   handle_movsi (latehalf);
 
   /* Undo the adds we just did.  */
@@ -3613,7 +3647,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
   if (scratch_reg
       && reload_in_progress && GET_CODE (operand0) == REG
       && REGNO (operand0) >= FIRST_PSEUDO_REGISTER)
-    operand0 = reg_equiv_mem[REGNO (operand0)];
+    operand0 = reg_equiv_mem (REGNO (operand0));
   else if (scratch_reg
           && reload_in_progress && GET_CODE (operand0) == SUBREG
           && GET_CODE (SUBREG_REG (operand0)) == REG
@@ -3622,15 +3656,15 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
      /* We must not alter SUBREG_BYTE (operand0) since that would confuse
        the code which tracks sets/uses for delete_output_reload.  */
       rtx temp = gen_rtx_SUBREG (GET_MODE (operand0),
-                                reg_equiv_mem [REGNO (SUBREG_REG (operand0))],
+                                reg_equiv_mem (REGNO (SUBREG_REG (operand0))),
                                 SUBREG_BYTE (operand0));
-      operand0 = alter_subreg (&temp);
+      operand0 = alter_subreg (&temp, true);
     }
 
   if (scratch_reg
       && reload_in_progress && GET_CODE (operand1) == REG
       && REGNO (operand1) >= FIRST_PSEUDO_REGISTER)
-    operand1 = reg_equiv_mem[REGNO (operand1)];
+    operand1 = reg_equiv_mem (REGNO (operand1));
   else if (scratch_reg
           && reload_in_progress && GET_CODE (operand1) == SUBREG
           && GET_CODE (SUBREG_REG (operand1)) == REG
@@ -3639,9 +3673,9 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
      /* We must not alter SUBREG_BYTE (operand0) since that would confuse
        the code which tracks sets/uses for delete_output_reload.  */
       rtx temp = gen_rtx_SUBREG (GET_MODE (operand1),
-                                reg_equiv_mem [REGNO (SUBREG_REG (operand1))],
+                                reg_equiv_mem (REGNO (SUBREG_REG (operand1))),
                                 SUBREG_BYTE (operand1));
-      operand1 = alter_subreg (&temp);
+      operand1 = alter_subreg (&temp, true);
     }
 
   if (scratch_reg && reload_in_progress && GET_CODE (operand0) == MEM
@@ -4184,7 +4218,8 @@ notice_update_cc (rtx exp, rtx insn)
       && GET_MODE_CLASS (GET_MODE (XEXP (cc_status.value2, 0))) == MODE_FLOAT)
     {
       cc_status.flags = CC_IN_68881;
-      if (!FP_REG_P (XEXP (cc_status.value2, 0)))
+      if (!FP_REG_P (XEXP (cc_status.value2, 0))
+         && FP_REG_P (XEXP (cc_status.value2, 1)))
        cc_status.flags |= CC_REVERSED;
     }
 }
@@ -4522,9 +4557,9 @@ m68k_get_reloc_decoration (enum m68k_reloc reloc)
     }
 }
 
-/* m68k implementation of OUTPUT_ADDR_CONST_EXTRA.  */
+/* m68k implementation of TARGET_OUTPUT_ADDR_CONST_EXTRA.  */
 
-bool
+static bool
 m68k_output_addr_const_extra (FILE *file, rtx x)
 {
   if (GET_CODE (x) == UNSPEC)
@@ -4534,7 +4569,8 @@ m68k_output_addr_const_extra (FILE *file, rtx x)
        case UNSPEC_RELOC16:
        case UNSPEC_RELOC32:
          output_addr_const (file, XVECEXP (x, 0, 0));
-         fputs (m68k_get_reloc_decoration (INTVAL (XVECEXP (x, 0, 1))), file);
+         fputs (m68k_get_reloc_decoration
+                ((enum m68k_reloc) INTVAL (XVECEXP (x, 0, 1))), file);
          return true;
 
        default:
@@ -4556,6 +4592,55 @@ m68k_output_dwarf_dtprel (FILE *file, int size, rtx x)
   fputs ("@TLSLDO+0x8000", file);
 }
 
+/* In the name of slightly smaller debug output, and to cater to
+   general assembler lossage, recognize various UNSPEC sequences
+   and turn them back into a direct symbol reference.  */
+
+static rtx
+m68k_delegitimize_address (rtx orig_x)
+{
+  rtx x;
+  struct m68k_address addr;
+  rtx unspec;
+
+  orig_x = delegitimize_mem_from_attrs (orig_x);
+  x = orig_x;
+  if (MEM_P (x))
+    x = XEXP (x, 0);
+
+  if (GET_CODE (x) != PLUS || GET_MODE (x) != Pmode)
+    return orig_x;
+
+  if (!m68k_decompose_address (GET_MODE (x), x, false, &addr)
+      || addr.offset == NULL_RTX
+      || GET_CODE (addr.offset) != CONST)
+    return orig_x;
+
+  unspec = XEXP (addr.offset, 0);
+  if (GET_CODE (unspec) == PLUS && CONST_INT_P (XEXP (unspec, 1)))
+    unspec = XEXP (unspec, 0);
+  if (GET_CODE (unspec) != UNSPEC 
+      || (XINT (unspec, 1) != UNSPEC_RELOC16
+         && XINT (unspec, 1) != UNSPEC_RELOC32))
+    return orig_x;
+  x = XVECEXP (unspec, 0, 0);
+  gcc_assert (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF);
+  if (unspec != XEXP (addr.offset, 0))
+    x = gen_rtx_PLUS (Pmode, x, XEXP (XEXP (addr.offset, 0), 1));
+  if (addr.index)
+    {
+      rtx idx = addr.index;
+      if (addr.scale != 1)
+       idx = gen_rtx_MULT (Pmode, idx, GEN_INT (addr.scale));
+      x = gen_rtx_PLUS (Pmode, idx, x);
+    }
+  if (addr.base)
+    x = gen_rtx_PLUS (Pmode, addr.base, x);
+  if (MEM_P (orig_x))
+    x = replace_equiv_address_nv (orig_x, x);
+  return x;
+}
+  
 \f
 /* A C compound statement to output to stdio stream STREAM the
    assembler syntax for an instruction operand that is a memory
@@ -4829,7 +4914,7 @@ output_andsi3 (rtx *operands)
       return "and%.w %2,%0";
     }
   if (GET_CODE (operands[2]) == CONST_INT
-      && (logval = exact_log2 (~ INTVAL (operands[2]))) >= 0
+      && (logval = exact_log2 (~ INTVAL (operands[2]) & 0xffffffff)) >= 0
       && (DATA_REG_P (operands[0])
           || offsettable_memref_p (operands[0])))
     {
@@ -4866,7 +4951,7 @@ output_iorsi3 (rtx *operands)
       return "or%.w %2,%0";
     }
   if (GET_CODE (operands[2]) == CONST_INT
-      && (logval = exact_log2 (INTVAL (operands[2]))) >= 0
+      && (logval = exact_log2 (INTVAL (operands[2]) & 0xffffffff)) >= 0
       && (DATA_REG_P (operands[0])
          || offsettable_memref_p (operands[0])))
     {
@@ -4901,7 +4986,7 @@ output_xorsi3 (rtx *operands)
       return "eor%.w %2,%0";
     }
   if (GET_CODE (operands[2]) == CONST_INT
-      && (logval = exact_log2 (INTVAL (operands[2]))) >= 0
+      && (logval = exact_log2 (INTVAL (operands[2]) & 0xffffffff)) >= 0
       && (DATA_REG_P (operands[0])
          || offsettable_memref_p (operands[0])))
     {
@@ -4946,13 +5031,18 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
                      HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
                      tree function)
 {
-  rtx this_slot, offset, addr, mem, insn;
+  rtx this_slot, offset, addr, mem, insn, tmp;
+
+  /* Avoid clobbering the struct value reg by using the
+     static chain reg as a temporary.  */
+  tmp = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
 
   /* Pretend to be a post-reload pass while generating rtl.  */
   reload_completed = 1;
 
   /* The "this" pointer is stored at 4(%sp).  */
-  this_slot = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, 4));
+  this_slot = gen_rtx_MEM (Pmode, plus_constant (Pmode,
+                                                stack_pointer_rtx, 4));
 
   /* Add DELTA to THIS.  */
   if (delta != 0)
@@ -4973,15 +5063,15 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
   if (vcall_offset != 0)
     {
       /* Set the static chain register to *THIS.  */
-      emit_move_insn (static_chain_rtx, this_slot);
-      emit_move_insn (static_chain_rtx, gen_rtx_MEM (Pmode, static_chain_rtx));
+      emit_move_insn (tmp, this_slot);
+      emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
 
       /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET.  */
-      addr = plus_constant (static_chain_rtx, vcall_offset);
+      addr = plus_constant (Pmode, tmp, vcall_offset);
       if (!m68k_legitimate_address_p (Pmode, addr, true))
        {
-         emit_insn (gen_rtx_SET (VOIDmode, static_chain_rtx, addr));
-         addr = static_chain_rtx;
+         emit_insn (gen_rtx_SET (VOIDmode, tmp, addr));
+         addr = tmp;
        }
 
       /* Load the offset into %d0 and add it to THIS.  */
@@ -5007,8 +5097,8 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
          SET_REGNO (pic_offset_table_rtx, STATIC_CHAIN_REGNUM);
          emit_insn (gen_load_got (pic_offset_table_rtx));
        }
-      legitimize_pic_address (XEXP (mem, 0), Pmode, static_chain_rtx);
-      mem = replace_equiv_address (mem, static_chain_rtx);
+      legitimize_pic_address (XEXP (mem, 0), Pmode, tmp);
+      mem = replace_equiv_address (mem, tmp);
     }
   insn = emit_call_insn (gen_sibcall (mem, const0_rtx));
   SIBLING_CALL_P (insn) = 1;
@@ -5026,7 +5116,6 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
   /* Restore the original PIC register.  */
   if (flag_pic)
     SET_REGNO (pic_offset_table_rtx, PIC_REG);
-  free_after_compilation (cfun);
 }
 
 /* Worker function for TARGET_STRUCT_VALUE_RTX.  */
@@ -5169,6 +5258,9 @@ m68k_libcall_value (enum machine_mode mode)
   return gen_rtx_REG (mode, m68k_libcall_value_in_a0_p ? A0_REG : D0_REG);
 }
 
+/* Location in which function value is returned.
+   NOTE: Due to differences in ABIs, don't call this function directly,
+   use FUNCTION_VALUE instead.  */
 rtx
 m68k_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
 {
@@ -5488,7 +5580,6 @@ m68k_sched_attr_opx_type (rtx insn, int address_p)
 
     default:
       gcc_unreachable ();
-      return 0;
     }
 }
 
@@ -5532,7 +5623,6 @@ m68k_sched_attr_opy_type (rtx insn, int address_p)
 
     default:
       gcc_unreachable ();
-      return 0;
     }
 }
 
@@ -5638,7 +5728,6 @@ m68k_sched_attr_size (rtx insn)
 
     default:
       gcc_unreachable ();
-      return 0;
     }
 }
 
@@ -5670,7 +5759,6 @@ sched_get_opxy_mem_type (rtx insn, bool opx_p)
 
        default:
          gcc_unreachable ();
-         return 0;
        }
     }
   else
@@ -5696,7 +5784,6 @@ sched_get_opxy_mem_type (rtx insn, bool opx_p)
 
        default:
          gcc_unreachable ();
-         return 0;
        }
     }
 }
@@ -5729,7 +5816,6 @@ m68k_sched_attr_op_mem (rtx insn)
 
        default:
          gcc_unreachable ();
-         return 0;
        }
     }
 
@@ -5748,7 +5834,6 @@ m68k_sched_attr_op_mem (rtx insn)
 
        default:
          gcc_unreachable ();
-         return 0;
        }
     }
 
@@ -5802,26 +5887,6 @@ m68k_sched_attr_op_mem (rtx insn)
   return OP_MEM_I1;
 }
 
-/* Jump instructions types.  Indexed by INSN_UID.
-   The same rtl insn can be expanded into different asm instructions
-   depending on the cc0_status.  To properly determine type of jump
-   instructions we scan instruction stream and map jumps types to this
-   array.  */
-static enum attr_type *sched_branch_type;
-
-/* Return the type of the jump insn.  */
-enum attr_type
-m68k_sched_branch_type (rtx insn)
-{
-  enum attr_type type;
-
-  type = sched_branch_type[INSN_UID (insn)];
-
-  gcc_assert (type != 0);
-
-  return type;
-}
-
 /* Data for ColdFire V4 index bypass.
    Producer modifies register that is used as index in consumer with
    specified scale.  */
@@ -6008,7 +6073,14 @@ m68k_sched_variable_issue (FILE *sched_dump ATTRIBUTE_UNUSED,
          gcc_unreachable ();
        }
 
-      gcc_assert (insn_size <= sched_ib.filled);
+      if (insn_size > sched_ib.filled)
+       /* Scheduling for register pressure does not always take DFA into
+          account.  Workaround instruction buffer not being filled enough.  */
+       {
+         gcc_assert (sched_pressure == SCHED_PRESSURE_WEIGHTED);
+         insn_size = sched_ib.filled;
+       }
+
       --can_issue_more;
     }
   else if (GET_CODE (PATTERN (insn)) == ASM_INPUT
@@ -6030,7 +6102,7 @@ m68k_sched_first_cycle_multipass_dfa_lookahead (void)
   return m68k_sched_issue_rate () - 1;
 }
 
-/* Implementation of targetm.sched.md_init_global () hook.
+/* Implementation of targetm.sched.init_global () hook.
    It is invoked once per scheduling pass and is used here
    to initialize scheduler constants.  */
 static void
@@ -6038,20 +6110,6 @@ m68k_sched_md_init_global (FILE *sched_dump ATTRIBUTE_UNUSED,
                           int sched_verbose ATTRIBUTE_UNUSED,
                           int n_insns ATTRIBUTE_UNUSED)
 {
-  /* Init branch types.  */
-  {
-    rtx insn;
-
-    sched_branch_type = XCNEWVEC (enum attr_type, get_max_uid () + 1);
-
-    for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
-      {
-       if (JUMP_P (insn))
-         /* !!! FIXME: Implement real scan here.  */
-         sched_branch_type[INSN_UID (insn)] = TYPE_BCC;
-      }
-  }
-
 #ifdef ENABLE_CHECKING
   /* Check that all instructions have DFA reservations and
      that all instructions can be issued from a clean state.  */
@@ -6133,12 +6191,9 @@ m68k_sched_md_finish_global (FILE *dump ATTRIBUTE_UNUSED,
   sched_ib.records.adjust = NULL;
   sched_ib.records.n_insns = 0;
   max_insn_size = 0;
-
-  free (sched_branch_type);
-  sched_branch_type = NULL;
 }
 
-/* Implementation of targetm.sched.md_init () hook.
+/* Implementation of targetm.sched.init () hook.
    It is invoked each time scheduler starts on the new block (basic block or
    extended basic block).  */
 static void
@@ -6214,7 +6269,8 @@ m68k_sched_dfa_post_advance_cycle (void)
   while (--i >= 0)
     {
       if (state_transition (curr_state, sched_ib.insn) >= 0)
-       gcc_unreachable ();
+       /* Pick up scheduler state.  */
+       ++sched_ib.filled;
     }
 }
 
@@ -6379,4 +6435,86 @@ m68k_sched_indexed_address_bypass_p (rtx pro, rtx con)
     }
 }
 
+/* We generate a two-instructions program at M_TRAMP :
+       movea.l &CHAIN_VALUE,%a0
+       jmp FNADDR
+   where %a0 can be modified by changing STATIC_CHAIN_REGNUM.  */
+
+static void
+m68k_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx mem;
+
+  gcc_assert (ADDRESS_REGNO_P (STATIC_CHAIN_REGNUM));
+
+  mem = adjust_address (m_tramp, HImode, 0);
+  emit_move_insn (mem, GEN_INT(0x207C + ((STATIC_CHAIN_REGNUM-8) << 9)));
+  mem = adjust_address (m_tramp, SImode, 2);
+  emit_move_insn (mem, chain_value);
+
+  mem = adjust_address (m_tramp, HImode, 6);
+  emit_move_insn (mem, GEN_INT(0x4EF9));
+  mem = adjust_address (m_tramp, SImode, 8);
+  emit_move_insn (mem, fnaddr);
+
+  FINALIZE_TRAMPOLINE (XEXP (m_tramp, 0));
+}
+
+/* On the 68000, the RTS insn cannot pop anything.
+   On the 68010, the RTD insn may be used to pop them if the number
+     of args is fixed, but if the number is variable then the caller
+     must pop them all.  RTD can't be used for library calls now
+     because the library is compiled with the Unix compiler.
+   Use of RTD is a selectable option, since it is incompatible with
+   standard Unix calling sequences.  If the option is not selected,
+   the caller must always pop the args.  */
+
+static int
+m68k_return_pops_args (tree fundecl, tree funtype, int size)
+{
+  return ((TARGET_RTD
+          && (!fundecl
+              || TREE_CODE (fundecl) != IDENTIFIER_NODE)
+          && (!stdarg_p (funtype)))
+         ? size : 0);
+}
+
+/* Make sure everything's fine if we *don't* have a given processor.
+   This assumes that putting a register in fixed_regs will keep the
+   compiler's mitts completely off it.  We don't bother to zero it out
+   of register classes.  */
+
+static void
+m68k_conditional_register_usage (void)
+{
+  int i;
+  HARD_REG_SET x;
+  if (!TARGET_HARD_FLOAT)
+    {
+      COPY_HARD_REG_SET (x, reg_class_contents[(int)FP_REGS]);
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+        if (TEST_HARD_REG_BIT (x, i))
+         fixed_regs[i] = call_used_regs[i] = 1;
+    }
+  if (flag_pic)
+    fixed_regs[PIC_REG] = call_used_regs[PIC_REG] = 1;
+}
+
+static void
+m68k_init_sync_libfuncs (void)
+{
+  init_sync_libfuncs (UNITS_PER_WORD);
+}
+
+/* Implements EPILOGUE_USES.  All registers are live on exit from an
+   interrupt routine.  */
+bool
+m68k_epilogue_uses (int regno ATTRIBUTE_UNUSED)
+{
+  return (reload_completed
+         && (m68k_get_function_kind (current_function_decl)
+             == m68k_fk_interrupt_handler));
+}
+
 #include "gt-m68k.h"