OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / config / mn10300 / mn10300.c
index 2c68dcb..b55ca37 100644 (file)
@@ -1,13 +1,13 @@
 /* Subroutines for insn-output.c for Matsushita MN10300 series
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-   Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
    Contributed by Jeff Law (law@cygnus.com).
 
 This file is part of GCC.
 
 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.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +16,8 @@ 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 GCC; 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/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -28,17 +27,18 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.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 "flags.h"
 #include "recog.h"
+#include "reload.h"
 #include "expr.h"
 #include "optabs.h"
 #include "function.h"
 #include "obstack.h"
+#include "diagnostic-core.h"
 #include "toplev.h"
 #include "tm_p.h"
 #include "target.h"
@@ -54,29 +54,50 @@ int mn10300_unspec_int_label_counter;
    symbol names from register names.  */
 int mn10300_protect_label;
 
+/* The selected processor.  */
+enum processor_type mn10300_processor = PROCESSOR_DEFAULT;
+
 /* The size of the callee register save area.  Right now we save everything
    on entry since it costs us nothing in code size.  It does cost us from a
    speed standpoint, so we want to optimize this sooner or later.  */
-#define REG_SAVE_BYTES (4 * regs_ever_live[2] \
-                       + 4 * regs_ever_live[3] \
-                       + 4 * regs_ever_live[6] \
-                       + 4 * regs_ever_live[7] \
-                       + 16 * (regs_ever_live[14] || regs_ever_live[15] \
-                               || regs_ever_live[16] || regs_ever_live[17]))
+#define REG_SAVE_BYTES (4 * df_regs_ever_live_p (2)    \
+                       + 4 * df_regs_ever_live_p (3)   \
+                       + 4 * df_regs_ever_live_p (6)   \
+                       + 4 * df_regs_ever_live_p (7)                   \
+                       + 16 * (df_regs_ever_live_p (14) || df_regs_ever_live_p (15) \
+                               || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)))
 
 
+static bool mn10300_handle_option (size_t, const char *, int);
+static bool mn10300_legitimate_address_p (enum machine_mode, rtx, bool);
 static int mn10300_address_cost_1 (rtx, int *);
-static int mn10300_address_cost (rtx);
-static bool mn10300_rtx_costs (rtx, int, int, int *);
+static int mn10300_address_cost (rtx, bool);
+static bool mn10300_rtx_costs (rtx, int, int, int *, bool);
 static void mn10300_file_start (void);
-static bool mn10300_return_in_memory (tree, tree);
+static bool mn10300_return_in_memory (const_tree, const_tree);
 static rtx mn10300_builtin_saveregs (void);
-
+static void mn10300_va_start (tree, rtx);
+static rtx mn10300_legitimize_address (rtx, rtx, enum machine_mode);
+static bool mn10300_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+                                      const_tree, bool);
+static int mn10300_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                     tree, bool);
+static unsigned int mn10300_case_values_threshold (void);
+static void mn10300_encode_section_info (tree, rtx, int);
+static void mn10300_asm_trampoline_template (FILE *);
+static void mn10300_trampoline_init (rtx, tree, rtx);
+static rtx mn10300_function_value (const_tree, const_tree, bool);
+static rtx mn10300_libcall_value (enum machine_mode, const_rtx);
+static void mn10300_asm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
+static bool mn10300_can_output_mi_thunk (const_tree, HOST_WIDE_INT, HOST_WIDE_INT, const_tree);
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
 
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS mn10300_legitimize_address
+
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS mn10300_rtx_costs
 #undef TARGET_ADDRESS_COST
@@ -87,21 +108,84 @@ static rtx mn10300_builtin_saveregs (void);
 #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 MASK_MULT_BUG | MASK_PTR_A0D0
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION mn10300_handle_option
+
 #undef  TARGET_ENCODE_SECTION_INFO
 #define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info
 
 #undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
-
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY mn10300_return_in_memory
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE mn10300_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES mn10300_arg_partial_bytes
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS mn10300_builtin_saveregs
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START mn10300_va_start
+
+#undef TARGET_CASE_VALUES_THRESHOLD
+#define TARGET_CASE_VALUES_THRESHOLD mn10300_case_values_threshold
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P    mn10300_legitimate_address_p
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE mn10300_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE mn10300_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE mn10300_libcall_value
+
+#undef  TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK      mn10300_asm_output_mi_thunk
+#undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK  mn10300_can_output_mi_thunk
 
-static void mn10300_encode_section_info (tree, rtx, int);
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+mn10300_handle_option (size_t code,
+                      const char *arg ATTRIBUTE_UNUSED,
+                      int value)
+{
+  switch (code)
+    {
+    case OPT_mam33:
+      mn10300_processor = value ? PROCESSOR_AM33 : PROCESSOR_MN10300;
+      return true;
+    case OPT_mam33_2:
+      mn10300_processor = (value
+                          ? PROCESSOR_AM33_2
+                          : MIN (PROCESSOR_AM33, PROCESSOR_DEFAULT));
+      return true;
+    default:
+      return true;
+    }
+}
+
+/* Implement OVERRIDE_OPTIONS.  */
+
+void
+mn10300_override_options (void)
+{
+  if (TARGET_AM33)
+    target_flags &= ~MASK_MULT_BUG;
+}
+
 static void
 mn10300_file_start (void)
 {
@@ -172,7 +256,7 @@ print_operand (FILE *file, rtx x, int code)
                fprintf (file, "ul");
                break;
              default:
-               abort ();
+               gcc_unreachable ();
              }
            break;
          }
@@ -210,7 +294,7 @@ print_operand (FILE *file, rtx x, int code)
            fprintf (file, "cs");
            break;
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
       case 'C':
@@ -226,7 +310,7 @@ print_operand (FILE *file, rtx x, int code)
        else
          print_operand (file, x, 0);
        break;
-     
+
       case 'D':
        switch (GET_CODE (x))
          {
@@ -241,7 +325,7 @@ print_operand (FILE *file, rtx x, int code)
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
@@ -300,7 +384,7 @@ print_operand (FILE *file, rtx x, int code)
            }
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
@@ -336,10 +420,10 @@ print_operand (FILE *file, rtx x, int code)
                      fprintf (file, "0x%lx", val[1]);
                      break;;
                    case SFmode:
-                     abort ();
+                     gcc_unreachable ();
                    case VOIDmode:
                    case DImode:
-                     print_operand_address (file, 
+                     print_operand_address (file,
                                             GEN_INT (CONST_DOUBLE_HIGH (x)));
                      break;
                    default:
@@ -357,7 +441,7 @@ print_operand (FILE *file, rtx x, int code)
            }
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
@@ -371,14 +455,12 @@ print_operand (FILE *file, rtx x, int code)
        break;
 
       case 'N':
-       if (INTVAL (x) < -128 || INTVAL (x) > 255)
-         abort ();
+       gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
        fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff));
        break;
 
       case 'U':
-       if (INTVAL (x) < -128 || INTVAL (x) > 255)
-         abort ();
+       gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
        fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
        break;
 
@@ -436,7 +518,7 @@ print_operand (FILE *file, rtx x, int code)
            print_operand_address (file, x);
            break;
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
    }
@@ -466,7 +548,7 @@ print_operand_address (FILE *file, rtx addr)
            && REG_OK_FOR_BASE_P (XEXP (addr, 1)))
          base = XEXP (addr, 1), index = XEXP (addr, 0);
        else
-         abort ();
+         gcc_unreachable ();
        print_operand (file, index, 0);
        fputc (',', file);
        print_operand (file, base, 0);;
@@ -491,7 +573,7 @@ fp_regs_to_save (void)
     return 0;
 
   for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
-    if (regs_ever_live[i] && ! call_used_regs[i])
+    if (df_regs_ever_live_p (i) && ! call_really_used_regs[i])
       ++n;
 
   return n;
@@ -500,7 +582,7 @@ fp_regs_to_save (void)
 /* Print a set of registers in the format required by "movm" and "ret".
    Register K is saved if bit K of MASK is set.  The data and address
    registers can be stored individually, but the extended registers cannot.
-   We assume that the mask alread takes that into account.  For instance,
+   We assume that the mask already takes that into account.  For instance,
    bits 14 to 17 must have the same value.  */
 
 void
@@ -523,8 +605,7 @@ mn10300_print_reg_list (FILE *file, int mask)
 
   if ((mask & 0x3c000) != 0)
     {
-      if ((mask & 0x3c000) != 0x3c000)
-       abort();
+      gcc_assert ((mask & 0x3c000) == 0x3c000);
       if (need_comma)
        fputc (',', file);
       fputs ("exreg1", file);
@@ -538,21 +619,21 @@ int
 can_use_return_insn (void)
 {
   /* size includes the fixed stack space needed for function calls.  */
-  int size = get_frame_size () + current_function_outgoing_args_size;
+  int size = get_frame_size () + crtl->outgoing_args_size;
 
   /* And space for the return pointer.  */
-  size += current_function_outgoing_args_size ? 4 : 0;
+  size += crtl->outgoing_args_size ? 4 : 0;
 
   return (reload_completed
          && size == 0
-         && !regs_ever_live[2]
-         && !regs_ever_live[3]
-         && !regs_ever_live[6]
-         && !regs_ever_live[7]
-         && !regs_ever_live[14]
-         && !regs_ever_live[15]
-         && !regs_ever_live[16]
-         && !regs_ever_live[17]
+         && !df_regs_ever_live_p (2)
+         && !df_regs_ever_live_p (3)
+         && !df_regs_ever_live_p (6)
+         && !df_regs_ever_live_p (7)
+         && !df_regs_ever_live_p (14)
+         && !df_regs_ever_live_p (15)
+         && !df_regs_ever_live_p (16)
+         && !df_regs_ever_live_p (17)
          && fp_regs_to_save () == 0
          && !frame_pointer_needed);
 }
@@ -569,7 +650,7 @@ mn10300_get_live_callee_saved_regs (void)
 
   mask = 0;
   for (i = 0; i <= LAST_EXTENDED_REGNUM; i++)
-    if (regs_ever_live[i] && ! call_used_regs[i])
+    if (df_regs_ever_live_p (i) && ! call_really_used_regs[i])
       mask |= (1 << i);
   if ((mask & 0x3c000) != 0)
     mask |= 0x3c000;
@@ -650,8 +731,8 @@ expand_prologue (void)
   HOST_WIDE_INT size;
 
   /* SIZE includes the fixed stack space needed for function calls.  */
-  size = get_frame_size () + current_function_outgoing_args_size;
-  size += (current_function_outgoing_args_size ? 4 : 0);
+  size = get_frame_size () + crtl->outgoing_args_size;
+  size += (crtl->outgoing_args_size ? 4 : 0);
 
   /* If we use any of the callee-saved registers, save them now.  */
   mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
@@ -756,7 +837,7 @@ expand_prologue (void)
         frame pointer, size is nonzero and the user hasn't
         changed the calling conventions of a0.  */
       if (! frame_pointer_needed && size
-         && call_used_regs[FIRST_ADDRESS_REGNUM]
+         && call_really_used_regs [FIRST_ADDRESS_REGNUM]
          && ! fixed_regs[FIRST_ADDRESS_REGNUM])
        {
          /* Insn: add -(size + 4 * num_regs_to_save), sp.  */
@@ -780,7 +861,7 @@ expand_prologue (void)
 
       /* Consider alternative save_a0_no_merge if the user hasn't
         changed the calling conventions of a0.  */
-      if (call_used_regs[FIRST_ADDRESS_REGNUM]
+      if (call_really_used_regs [FIRST_ADDRESS_REGNUM]
          && ! fixed_regs[FIRST_ADDRESS_REGNUM])
        {
          /* Insn: add -4 * num_regs_to_save, sp.  */
@@ -835,9 +916,9 @@ expand_prologue (void)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
-         
+
       /* Now prepare register a0, if we have decided to use it.  */
       switch (strategy)
        {
@@ -855,14 +936,14 @@ expand_prologue (void)
            emit_insn (gen_addsi3 (reg, reg, GEN_INT (xsize)));
          reg = gen_rtx_POST_INC (SImode, reg);
          break;
-         
+
        default:
-         abort ();
+         gcc_unreachable ();
        }
-      
+
       /* Now actually save the FP registers.  */
       for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_really_used_regs [i])
          {
            rtx addr;
 
@@ -879,7 +960,7 @@ expand_prologue (void)
                  }
                else
                  addr = stack_pointer_rtx;
-               
+
                xsize += 4;
              }
 
@@ -899,24 +980,8 @@ expand_prologue (void)
     emit_insn (gen_addsi3 (stack_pointer_rtx,
                           stack_pointer_rtx,
                           GEN_INT (-size)));
-  if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-    {
-      rtx insn = get_last_insn ();
-      rtx last = emit_insn (gen_GOTaddr2picreg ());
-
-      /* Mark these insns as possibly dead.  Sometimes, flow2 may
-        delete all uses of the PIC register.  In this case, let it
-        delete the initialization too.  */
-      do
-       {
-         insn = NEXT_INSN (insn);
-
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                               const0_rtx,
-                                               REG_NOTES (insn));
-       }
-      while (insn != last);
-    }
+  if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+    emit_insn (gen_GOTaddr2picreg ());
 }
 
 void
@@ -925,8 +990,8 @@ expand_epilogue (void)
   HOST_WIDE_INT size;
 
   /* SIZE includes the fixed stack space needed for function calls.  */
-  size = get_frame_size () + current_function_outgoing_args_size;
-  size += (current_function_outgoing_args_size ? 4 : 0);
+  size = get_frame_size () + crtl->outgoing_args_size;
+  size += (crtl->outgoing_args_size ? 4 : 0);
 
   if (TARGET_AM33_2 && fp_regs_to_save ())
     {
@@ -1014,7 +1079,7 @@ expand_epilogue (void)
 
          /* Consider using a1 in post-increment mode, as long as the
             user hasn't changed the calling conventions of a1.  */
-         if (call_used_regs[FIRST_ADDRESS_REGNUM+1]
+         if (call_really_used_regs [FIRST_ADDRESS_REGNUM + 1]
              && ! fixed_regs[FIRST_ADDRESS_REGNUM+1])
            {
              /* Insn: mov sp,a1.  */
@@ -1064,7 +1129,7 @@ expand_epilogue (void)
                                              + REG_SAVE_BYTES - 252)));
              size = 252 - REG_SAVE_BYTES - 4 * num_regs_to_save;
              break;
-             
+
            case restore_a1:
              reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM + 1);
              emit_insn (gen_movsi (reg, stack_pointer_rtx));
@@ -1073,7 +1138,7 @@ expand_epilogue (void)
              break;
 
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
 
@@ -1082,10 +1147,10 @@ expand_epilogue (void)
        reg = gen_rtx_POST_INC (SImode, reg);
 
       for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_really_used_regs [i])
          {
            rtx addr;
-           
+
            if (reg)
              addr = reg;
            else if (size)
@@ -1122,7 +1187,7 @@ expand_epilogue (void)
 
      If the stack size + register save area is more than 255 bytes,
      then the stack must be cut back here since the size + register
-     save size is too big for a ret/retf instruction. 
+     save size is too big for a ret/retf instruction.
 
      Else leave it alone, it will be cut back as part of the
      ret/retf instruction, or there wasn't any stack to begin with.
@@ -1144,10 +1209,10 @@ expand_epilogue (void)
     }
 
   /* Adjust the stack and restore callee-saved registers, if any.  */
-  if (size || regs_ever_live[2] || regs_ever_live[3]
-      || regs_ever_live[6] || regs_ever_live[7]
-      || regs_ever_live[14] || regs_ever_live[15]
-      || regs_ever_live[16] || regs_ever_live[17]
+  if (size || df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
+      || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
+      || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
+      || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
       || frame_pointer_needed)
     emit_jump_insn (gen_return_internal_regs
                    (GEN_INT (size + REG_SAVE_BYTES)));
@@ -1198,20 +1263,13 @@ notice_update_cc (rtx body, rtx insn)
        cc_status.mdep.fpCC = 1;
       break;
 
-    case CC_INVERT:
-      /* The insn is a compare instruction.  */
-      CC_STATUS_INIT;
-      cc_status.value1 = SET_SRC (body);
-      cc_status.flags |= CC_INVERTED;
-      break;
-
     case CC_CLOBBER:
       /* Insn doesn't leave CC in a usable state.  */
       CC_STATUS_INIT;
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -1294,36 +1352,31 @@ store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return mask;
 }
 
-/* Return true if OP is a valid call operand.  */
-
-int
-call_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (flag_pic)
-    return (EXTRA_CONSTRAINT (op, 'S') || GET_CODE (op) == REG);
-
-  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
-}
-
 /* What (if any) secondary registers are needed to move IN with mode
-   MODE into a register in register class CLASS. 
+   MODE into a register in register class RCLASS.
 
    We might be able to simplify this.  */
 enum reg_class
-secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
+mn10300_secondary_reload_class (enum reg_class rclass, enum machine_mode mode,
+                               rtx in)
 {
+  rtx inner = in;
+
+  /* Strip off any SUBREG expressions from IN.  Basically we want
+     to know if IN is a pseudo or (subreg (pseudo)) as those can
+     turn into MEMs during reload.  */
+  while (GET_CODE (inner) == SUBREG)
+    inner = SUBREG_REG (inner);
+
   /* Memory loads less than a full word wide can't have an
      address or stack pointer destination.  They must use
      a data register as an intermediate register.  */
   if ((GET_CODE (in) == MEM
-       || (GET_CODE (in) == REG
-          && REGNO (in) >= FIRST_PSEUDO_REGISTER)
-       || (GET_CODE (in) == SUBREG
-          && GET_CODE (SUBREG_REG (in)) == REG
-          && REGNO (SUBREG_REG (in)) >= FIRST_PSEUDO_REGISTER))
+       || (GET_CODE (inner) == REG
+          && REGNO (inner) >= FIRST_PSEUDO_REGISTER))
       && (mode == QImode || mode == HImode)
-      && (class == ADDRESS_REGS || class == SP_REGS
-         || class == SP_OR_ADDRESS_REGS))
+      && (rclass == ADDRESS_REGS || rclass == SP_REGS
+         || rclass == SP_OR_ADDRESS_REGS))
     {
       if (TARGET_AM33)
        return DATA_OR_EXTENDED_REGS;
@@ -1332,12 +1385,12 @@ secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
 
   /* We can't directly load sp + const_int into a data register;
      we must use an address register as an intermediate.  */
-  if (class != SP_REGS
-      && class != ADDRESS_REGS
-      && class != SP_OR_ADDRESS_REGS
-      && class != SP_OR_EXTENDED_REGS
-      && class != ADDRESS_OR_EXTENDED_REGS
-      && class != SP_OR_ADDRESS_OR_EXTENDED_REGS
+  if (rclass != SP_REGS
+      && rclass != ADDRESS_REGS
+      && rclass != SP_OR_ADDRESS_REGS
+      && rclass != SP_OR_EXTENDED_REGS
+      && rclass != ADDRESS_OR_EXTENDED_REGS
+      && rclass != SP_OR_ADDRESS_OR_EXTENDED_REGS
       && (in == stack_pointer_rtx
          || (GET_CODE (in) == PLUS
              && (XEXP (in, 0) == stack_pointer_rtx
@@ -1347,18 +1400,24 @@ secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
   if (GET_CODE (in) == PLUS
       && (XEXP (in, 0) == stack_pointer_rtx
          || XEXP (in, 1) == stack_pointer_rtx))
+    return GENERAL_REGS;
+
+  if (TARGET_AM33_2
+      && rclass == FP_REGS)
     {
-      if (TARGET_AM33)
-       return DATA_OR_EXTENDED_REGS;
-      return DATA_REGS;
-    }
-  if (TARGET_AM33_2 && class == FP_REGS
-      && GET_CODE (in) == MEM && ! OK_FOR_Q (in))
-    {
-      if (TARGET_AM33)
-       return DATA_OR_EXTENDED_REGS;
-      return DATA_REGS;
+      /* We can't load directly into an FP register from a     
+        constant address.  */
+      if (GET_CODE (in) == MEM
+         && CONSTANT_ADDRESS_P (XEXP (in, 0)))
+       return (TARGET_AM33 ? DATA_OR_EXTENDED_REGS : DATA_REGS);
+
+      /* Handle case were a pseudo may not get a hard register
+        but has an equivalent memory location defined.  */
+      if (GET_CODE (inner) == REG
+         && REGNO (inner) >= FIRST_PSEUDO_REGISTER
+         && reg_equiv_mem [REGNO (inner)]
+         && CONSTANT_ADDRESS_P (XEXP (reg_equiv_mem [REGNO (inner)], 0)))
+       return (TARGET_AM33 ? DATA_OR_EXTENDED_REGS : DATA_REGS);
     }
 
   /* Otherwise assume no secondary reloads are needed.  */
@@ -1372,10 +1431,10 @@ initial_offset (int from, int to)
      is the size of the callee register save area.  */
   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
     {
-      if (regs_ever_live[2] || regs_ever_live[3]
-         || regs_ever_live[6] || regs_ever_live[7]
-         || regs_ever_live[14] || regs_ever_live[15]
-         || regs_ever_live[16] || regs_ever_live[17]
+      if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
+         || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
+         || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
+         || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
          || fp_regs_to_save ()
          || frame_pointer_needed)
        return REG_SAVE_BYTES
@@ -1389,20 +1448,20 @@ initial_offset (int from, int to)
      area, and the fixed stack space needed for function calls (if any).  */
   if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     {
-      if (regs_ever_live[2] || regs_ever_live[3]
-         || regs_ever_live[6] || regs_ever_live[7]
-         || regs_ever_live[14] || regs_ever_live[15]
-         || regs_ever_live[16] || regs_ever_live[17]
+      if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
+         || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
+         || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
+         || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
          || fp_regs_to_save ()
          || frame_pointer_needed)
        return (get_frame_size () + REG_SAVE_BYTES
                + 4 * fp_regs_to_save ()
-               + (current_function_outgoing_args_size
-                  ? current_function_outgoing_args_size + 4 : 0)); 
+               + (crtl->outgoing_args_size
+                  ? crtl->outgoing_args_size + 4 : 0));
       else
        return (get_frame_size ()
-               + (current_function_outgoing_args_size
-                  ? current_function_outgoing_args_size + 4 : 0)); 
+               + (crtl->outgoing_args_size
+                  ? crtl->outgoing_args_size + 4 : 0));
     }
 
   /* The difference between the frame pointer and stack pointer is the sum
@@ -1410,19 +1469,21 @@ initial_offset (int from, int to)
      for function calls (if any).  */
   if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return (get_frame_size ()
-           + (current_function_outgoing_args_size
-              ? current_function_outgoing_args_size + 4 : 0)); 
+           + (crtl->outgoing_args_size
+              ? crtl->outgoing_args_size + 4 : 0));
 
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 static bool
-mn10300_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+mn10300_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   /* Return values > 8 bytes in length in memory.  */
-  return int_size_in_bytes (type) > 8 || TYPE_MODE (type) == BLKmode;
+  return (int_size_in_bytes (type) > 8
+         || int_size_in_bytes (type) == 0
+         || TYPE_MODE (type) == BLKmode);
 }
 
 /* Flush the argument registers to the stack for a stdarg function;
@@ -1432,82 +1493,61 @@ mn10300_builtin_saveregs (void)
 {
   rtx offset, mem;
   tree fntype = TREE_TYPE (current_function_decl);
-  int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
-                   && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-                       != void_type_node)))
+  int argadj = ((!stdarg_p (fntype))
                 ? UNITS_PER_WORD : 0);
-  int set = get_varargs_alias_set ();
+  alias_set_type set = get_varargs_alias_set ();
 
   if (argadj)
-    offset = plus_constant (current_function_arg_offset_rtx, argadj);
+    offset = plus_constant (crtl->args.arg_offset_rtx, argadj);
   else
-    offset = current_function_arg_offset_rtx;
+    offset = crtl->args.arg_offset_rtx;
 
-  mem = gen_rtx_MEM (SImode, current_function_internal_arg_pointer);
+  mem = gen_rtx_MEM (SImode, crtl->args.internal_arg_pointer);
   set_mem_alias_set (mem, set);
   emit_move_insn (mem, gen_rtx_REG (SImode, 0));
 
   mem = gen_rtx_MEM (SImode,
-                    plus_constant (current_function_internal_arg_pointer, 4));
+                    plus_constant (crtl->args.internal_arg_pointer, 4));
   set_mem_alias_set (mem, set);
   emit_move_insn (mem, gen_rtx_REG (SImode, 1));
 
   return copy_to_reg (expand_binop (Pmode, add_optab,
-                                   current_function_internal_arg_pointer,
+                                   crtl->args.internal_arg_pointer,
                                    offset, 0, 0, OPTAB_LIB_WIDEN));
 }
 
-void
+static void
 mn10300_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
   std_expand_builtin_va_start (valist, nextarg);
 }
 
-rtx
-mn10300_va_arg (tree valist, tree type)
-{
-  HOST_WIDE_INT align, rsize;
-  tree t, ptr, pptr;
-
-  /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  rsize = (((int_size_in_bytes (type) + align - 1) / align) * align);
-
-  t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist, 
-            build_int_2 ((rsize > 8 ? 4 : rsize), 0));
-  TREE_SIDE_EFFECTS (t) = 1;
+/* Return true when a parameter should be passed by reference.  */
 
-  ptr = build_pointer_type (type);
-
-  /* "Large" types are passed by reference.  */
-  if (rsize > 8)
-    {
-      pptr = build_pointer_type (ptr);
-      t = build1 (NOP_EXPR, pptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
+static bool
+mn10300_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                          enum machine_mode mode, const_tree type,
+                          bool named ATTRIBUTE_UNUSED)
+{
+  unsigned HOST_WIDE_INT size;
 
-      t = build1 (INDIRECT_REF, ptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
-    }
+  if (type)
+    size = int_size_in_bytes (type);
   else
-    {
-      t = build1 (NOP_EXPR, ptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
-    }
+    size = GET_MODE_SIZE (mode);
 
-  /* Calculate!  */
-  return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
+  return (size > 8 || size == 0);
 }
 
 /* Return an RTX to represent where a value with mode MODE will be returned
-   from a function.  If the result is 0, the argument is pushed.  */
+   from a function.  If the result is NULL_RTX, the argument is pushed.  */
 
 rtx
 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
              tree type, int named ATTRIBUTE_UNUSED)
 {
-  rtx result = 0;
+  rtx result = NULL_RTX;
   int size, align;
 
   /* We only support using 2 data registers as argument registers.  */
@@ -1527,35 +1567,35 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   /* Don't pass this arg via a register if all the argument registers
      are used up.  */
   if (cum->nbytes > nregs * UNITS_PER_WORD)
-    return 0;
+    return result;
 
   /* Don't pass this arg via a register if it would be split between
      registers and memory.  */
   if (type == NULL_TREE
       && cum->nbytes + size > nregs * UNITS_PER_WORD)
-    return 0;
+    return result;
 
   switch (cum->nbytes / UNITS_PER_WORD)
     {
     case 0:
-      result = gen_rtx_REG (mode, 0);
+      result = gen_rtx_REG (mode, FIRST_ARGUMENT_REGNUM);
       break;
     case 1:
-      result = gen_rtx_REG (mode, 1);
+      result = gen_rtx_REG (mode, FIRST_ARGUMENT_REGNUM + 1);
       break;
     default:
-      result = 0;
+      break;
     }
 
   return result;
 }
 
-/* Return the number of registers to use for an argument passed partially
-   in registers and partially in memory.  */
+/* Return the number of bytes of registers to use for an argument passed
+   partially in registers and partially in memory.  */
 
-int
-function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                           tree type, int named ATTRIBUTE_UNUSED)
+static int
+mn10300_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                          tree type, bool named ATTRIBUTE_UNUSED)
 {
   int size, align;
 
@@ -1587,7 +1627,57 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && cum->nbytes + size > nregs * UNITS_PER_WORD)
     return 0;
 
-  return (nregs * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD;
+  return nregs * UNITS_PER_WORD - cum->nbytes;
+}
+
+/* Return the location of the function's value.  This will be either
+   $d0 for integer functions, $a0 for pointers, or a PARALLEL of both
+   $d0 and $a0 if the -mreturn-pointer-on-do flag is set.  Note that
+   we only return the PARALLEL for outgoing values; we do not want
+   callers relying on this extra copy.  */
+
+static rtx
+mn10300_function_value (const_tree valtype,
+                       const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+                       bool outgoing)
+{
+  rtx rv;
+  enum machine_mode mode = TYPE_MODE (valtype);
+
+  if (! POINTER_TYPE_P (valtype))
+    return gen_rtx_REG (mode, FIRST_DATA_REGNUM);
+  else if (! TARGET_PTR_A0D0 || ! outgoing
+          || cfun->returns_struct)
+    return gen_rtx_REG (mode, FIRST_ADDRESS_REGNUM);
+
+  rv = gen_rtx_PARALLEL (mode, rtvec_alloc (2));
+  XVECEXP (rv, 0, 0)
+    = gen_rtx_EXPR_LIST (VOIDmode,
+                        gen_rtx_REG (mode, FIRST_ADDRESS_REGNUM),
+                        GEN_INT (0));
+
+  XVECEXP (rv, 0, 1)
+    = gen_rtx_EXPR_LIST (VOIDmode,
+                        gen_rtx_REG (mode, FIRST_DATA_REGNUM),
+                        GEN_INT (0));
+  return rv;
+}
+
+/* Implements TARGET_LIBCALL_VALUE.  */
+
+static rtx
+mn10300_libcall_value (enum machine_mode mode,
+                      const_rtx fun ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (mode, FIRST_DATA_REGNUM);
+}
+
+/* Implements FUNCTION_VALUE_REGNO_P.  */
+
+bool
+mn10300_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == FIRST_DATA_REGNUM || regno == FIRST_ADDRESS_REGNUM);
 }
 
 /* Output a tst insn.  */
@@ -1630,7 +1720,7 @@ output_tst (rtx operand, rtx insn)
        }
 
       /* Are we setting a data register to zero (this does not win for
-        address registers)? 
+        address registers)?
 
         If it's a call clobbered register, have we past a call?
 
@@ -1646,8 +1736,8 @@ output_tst (rtx operand, rtx insn)
              == REGNO_REG_CLASS (REGNO (operand)))
          && REGNO_REG_CLASS (REGNO (SET_DEST (set))) != EXTENDED_REGS
          && REGNO (SET_DEST (set)) != REGNO (operand)
-         && (!past_call 
-             || !call_used_regs[REGNO (SET_DEST (set))]))
+         && (!past_call
+             || ! call_really_used_regs [REGNO (SET_DEST (set))]))
        {
          rtx xoperands[2];
          xoperands[0] = operand;
@@ -1665,8 +1755,8 @@ output_tst (rtx operand, rtx insn)
              != REGNO_REG_CLASS (REGNO (operand)))
          && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == EXTENDED_REGS
          && REGNO (SET_DEST (set)) != REGNO (operand)
-         && (!past_call 
-             || !call_used_regs[REGNO (SET_DEST (set))]))
+         && (!past_call
+             || ! call_really_used_regs [REGNO (SET_DEST (set))]))
        {
          rtx xoperands[2];
          xoperands[0] = operand;
@@ -1693,24 +1783,6 @@ impossible_plus_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return 0;
 }
 
-/* Return 1 if X is a CONST_INT that is only 8 bits wide.  This is used
-   for the btst insn which may examine memory or a register (the memory
-   variant only allows an unsigned 8 bit integer).  */
-int
-const_8bit_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && INTVAL (op) >= 0
-         && INTVAL (op) < 256);
-}
-
-/* Return true if the operand is the 1.0f constant.  */
-int
-const_1f_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (op == CONST1_RTX (SFmode));
-}
-
 /* Similarly, but when using a zero_extract pattern for a btst where
    the source operand might end up in memory.  */
 int
@@ -1760,17 +1832,14 @@ symbolic_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
    OLDX is the address as it was before break_out_memory_refs was called.
    In some cases it is useful to look at this to decide what needs to be done.
 
-   MODE and WIN are passed so that this macro can use
-   GO_IF_LEGITIMATE_ADDRESS.
-
    Normally it is always safe for this macro to do nothing.  It exists to
    recognize opportunities to optimize the output.
 
    But on a few ports with segmented architectures and indexed addressing
    (mn10300, hppa) it is used to rewrite certain problematical addresses.  */
 rtx
-legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
-                   enum machine_mode mode ATTRIBUTE_UNUSED)
+mn10300_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+                           enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (flag_pic && ! legitimate_pic_operand_p (x))
     x = legitimize_pic_address (oldx, NULL_RTX);
@@ -1847,12 +1916,10 @@ legitimate_pic_operand_p (rtx x)
       && (XINT (x, 1) == UNSPEC_PIC
          || XINT (x, 1) == UNSPEC_GOT
          || XINT (x, 1) == UNSPEC_GOTOFF
-         || XINT (x, 1) == UNSPEC_PLT))
+         || XINT (x, 1) == UNSPEC_PLT
+         || XINT (x, 1) == UNSPEC_GOTSYM_OFF))
       return 1;
 
-  if (GET_CODE (x) == QUEUED)
-    return legitimate_pic_operand_p (QUEUED_VAR (x));
-
   fmt = GET_RTX_FORMAT (GET_CODE (x));
   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
     {
@@ -1871,6 +1938,69 @@ legitimate_pic_operand_p (rtx x)
   return 1;
 }
 
+/* Return TRUE if the address X, taken from a (MEM:MODE X) rtx, is
+   legitimate, and FALSE otherwise.
+
+   On the mn10300, the value in the address register must be
+   in the same memory space/segment as the effective address.
+
+   This is problematical for reload since it does not understand
+   that base+index != index+base in a memory reference.
+
+   Note it is still possible to use reg+reg addressing modes,
+   it's just much more difficult.  For a discussion of a possible
+   workaround and solution, see the comments in pa.c before the
+   function record_unscaled_index_insn_codes.  */
+
+bool
+mn10300_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+{
+  if (CONSTANT_ADDRESS_P (x)
+      && (! flag_pic || legitimate_pic_operand_p (x)))
+    return TRUE;
+
+  if (RTX_OK_FOR_BASE_P (x, strict))
+    return TRUE;
+
+  if (TARGET_AM33
+      && GET_CODE (x) == POST_INC
+      && RTX_OK_FOR_BASE_P (XEXP (x, 0), strict)
+      && (mode == SImode || mode == SFmode || mode == HImode))
+    return TRUE;
+
+  if (GET_CODE (x) == PLUS)
+    {
+      rtx base = 0, index = 0;
+
+      if (REG_P (XEXP (x, 0))
+         && REGNO_STRICT_OK_FOR_BASE_P (REGNO (XEXP (x, 0)), strict))
+       {
+         base = XEXP (x, 0);
+         index = XEXP (x, 1);
+       }
+
+      if (REG_P (XEXP (x, 1))
+         && REGNO_STRICT_OK_FOR_BASE_P (REGNO (XEXP (x, 1)), strict))
+       {
+         base = XEXP (x, 1);
+         index = XEXP (x, 0);
+       }
+
+      if (base != 0 && index != 0)
+       {
+         if (GET_CODE (index) == CONST_INT)
+           return TRUE;
+         if (GET_CODE (index) == CONST
+             && GET_CODE (XEXP (index, 0)) != PLUS
+             && (! flag_pic
+                 || legitimate_pic_operand_p (index)))
+           return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
 static int
 mn10300_address_cost_1 (rtx x, int *unsig)
 {
@@ -1895,7 +2025,7 @@ mn10300_address_cost_1 (rtx x, int *unsig)
          return 5;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
     case PLUS:
@@ -1909,7 +2039,7 @@ mn10300_address_cost_1 (rtx x, int *unsig)
     case EXPR_LIST:
     case SUBREG:
     case MEM:
-      return mn10300_address_cost (XEXP (x, 0));
+      return mn10300_address_cost (XEXP (x, 0), !optimize_size);
 
     case ZERO_EXTEND:
       *unsig = 1;
@@ -1931,40 +2061,27 @@ mn10300_address_cost_1 (rtx x, int *unsig)
     case LABEL_REF:
       return 8;
 
-    case ADDRESSOF:
-      switch (GET_CODE (XEXP (x, 0)))
-       {
-       case MEM:
-         return mn10300_address_cost (XEXP (x, 0));
-
-       case REG:
-         return 1;
-
-       default:
-         abort ();
-       }
-
     default:
-      abort ();
+      gcc_unreachable ();
 
     }
 }
 
 static int
-mn10300_address_cost (rtx x)
+mn10300_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
 {
   int s = 0;
   return mn10300_address_cost_1 (x, &s);
 }
 
 static bool
-mn10300_rtx_costs (rtx x, int code, int outer_code, int *total)
+mn10300_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
     case CONST_INT:
       /* Zeros are extremely cheap.  */
-      if (INTVAL (x) == 0 && outer_code == SET)
+      if (INTVAL (x) == 0 && (outer_code == SET || outer_code == COMPARE))
        *total = 0;
       /* If it fits in 8 bits, then it's still relatively cheap.  */
       else if (INT_8_BITS (INTVAL (x)))
@@ -1993,6 +2110,12 @@ mn10300_rtx_costs (rtx x, int code, int outer_code, int *total)
       *total = 8;
       return true;
 
+    case ZERO_EXTRACT:
+      /* This is cheap, we can use btst.  */
+      if (outer_code == COMPARE)
+       *total = 0;
+      return false;
+
    /* ??? This probably needs more work.  */
     case MOD:
     case DIV:
@@ -2028,7 +2151,7 @@ mn10300_wide_const_load_uses_clr (rtx operands[2])
        val[1] = INTVAL (high);
       }
       break;
-      
+
     case CONST_DOUBLE:
       if (GET_MODE (operands[1]) == DFmode)
        {
@@ -2044,7 +2167,7 @@ mn10300_wide_const_load_uses_clr (rtx operands[2])
          val[1] = CONST_DOUBLE_HIGH (operands[1]);
        }
       break;
-      
+
     default:
       return false;
     }
@@ -2068,3 +2191,106 @@ mn10300_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
   if (flag_pic)
     SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl);
 }
+
+/* Dispatch tables on the mn10300 are extremely expensive in terms of code
+   and readonly data size.  So we crank up the case threshold value to
+   encourage a series of if/else comparisons to implement many small switch
+   statements.  In theory, this value could be increased much more if we
+   were solely optimizing for space, but we keep it "reasonable" to avoid
+   serious code efficiency lossage.  */
+
+unsigned int mn10300_case_values_threshold (void)
+{
+  return 6;
+}
+
+/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
+
+static void
+mn10300_asm_trampoline_template (FILE *f)
+{
+  fprintf (f, "\tadd -4,sp\n");
+  fprintf (f, "\t.long 0x0004fffa\n");
+  fprintf (f, "\tmov (0,sp),a0\n");
+  fprintf (f, "\tadd 4,sp\n");
+  fprintf (f, "\tmov (13,a0),a1\n");   
+  fprintf (f, "\tmov (17,a0),a0\n");
+  fprintf (f, "\tjmp (a0)\n");
+  fprintf (f, "\t.long 0\n");
+  fprintf (f, "\t.long 0\n");
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT.  */
+
+static void
+mn10300_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+  rtx mem;
+
+  emit_block_move (m_tramp, assemble_trampoline_template (),
+                  GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+  mem = adjust_address (m_tramp, SImode, 0x14);
+  emit_move_insn (mem, chain_value);
+  mem = adjust_address (m_tramp, SImode, 0x18);
+  emit_move_insn (mem, fnaddr);
+}
+
+/* Output the assembler code for a C++ thunk function.
+   THUNK_DECL is the declaration for the thunk function itself, FUNCTION
+   is the decl for the target function.  DELTA is an immediate constant
+   offset to be added to the THIS parameter.  If VCALL_OFFSET is nonzero
+   the word at the adjusted address *(*THIS' + VCALL_OFFSET) should be
+   additionally added to THIS.  Finally jump to the entry point of
+   FUNCTION.  */
+
+static void
+mn10300_asm_output_mi_thunk (FILE *        file,
+                            tree          thunk_fndecl ATTRIBUTE_UNUSED,
+                            HOST_WIDE_INT delta,
+                            HOST_WIDE_INT vcall_offset,
+                            tree          function)
+{
+  const char * _this;
+
+  /* Get the register holding the THIS parameter.  Handle the case
+     where there is a hidden first argument for a returned structure.  */
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+    _this = reg_names [FIRST_ARGUMENT_REGNUM + 1];
+  else
+    _this = reg_names [FIRST_ARGUMENT_REGNUM];
+
+  fprintf (file, "\t%s Thunk Entry Point:\n", ASM_COMMENT_START);
+
+  if (delta)
+    fprintf (file, "\tadd %d, %s\n", (int) delta, _this);
+
+  if (vcall_offset)
+    {
+      const char * scratch = reg_names [FIRST_ADDRESS_REGNUM + 1];
+
+      fprintf (file, "\tmov %s, %s\n", _this, scratch);
+      fprintf (file, "\tmov (%s), %s\n", scratch, scratch);
+      fprintf (file, "\tadd %d, %s\n", (int) vcall_offset, scratch);
+      fprintf (file, "\tmov (%s), %s\n", scratch, scratch);
+      fprintf (file, "\tadd %s, %s\n", scratch, _this);
+    }
+
+  fputs ("\tjmp ", file);
+  assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+  putc ('\n', file);
+}
+
+/* Return true if mn10300_output_mi_thunk would be able to output the
+   assembler code for the thunk function specified by the arguments
+   it is passed, and false otherwise.  */
+
+static bool
+mn10300_can_output_mi_thunk (const_tree    thunk_fndecl ATTRIBUTE_UNUSED,
+                            HOST_WIDE_INT delta        ATTRIBUTE_UNUSED,
+                            HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                            const_tree    function     ATTRIBUTE_UNUSED)
+{
+  return true;
+}