OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / config / mn10300 / mn10300.c
index e4ef4bf..b55ca37 100644 (file)
@@ -1,24 +1,23 @@
 /* Subroutines for insn-output.c for Matsushita MN10300 series
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   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 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/>.  */
 
 #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"
@@ -48,27 +48,56 @@ Boston, MA 02111-1307, USA.  */
    UNSPEC_INT_LABELs.  */
 int mn10300_unspec_int_label_counter;
 
+/* This is used in the am33_2.0-linux-gnu port, in which global symbol
+   names are not prefixed by underscores, to tell whether to prefix a
+   label with a plus sign or not, so that the assembler can tell
+   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]))
-
-
-static int mn10300_address_cost_1 PARAMS ((rtx, int *));
-static int mn10300_address_cost PARAMS ((rtx));
-static bool mn10300_rtx_costs PARAMS ((rtx, int, int, int *));
-static void mn10300_file_start PARAMS ((void));
-
+#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, bool);
+static bool mn10300_rtx_costs (rtx, int, int, int *, bool);
+static void mn10300_file_start (void);
+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
@@ -79,14 +108,86 @@ static void mn10300_file_start PARAMS ((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
 
-static void mn10300_encode_section_info (tree, rtx, int);
+#undef TARGET_PROMOTE_PROTOTYPES
+#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
+
 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 ()
+mn10300_file_start (void)
 {
   default_file_start ();
 
@@ -101,10 +202,7 @@ mn10300_file_start ()
    FILE.  */
 
 void
-print_operand (file, x, code)
-     FILE *file;
-     rtx x;
-     int code;
+print_operand (FILE *file, rtx x, int code)
 {
   switch (code)
     {
@@ -158,7 +256,7 @@ print_operand (file, x, code)
                fprintf (file, "ul");
                break;
              default:
-               abort ();
+               gcc_unreachable ();
              }
            break;
          }
@@ -196,7 +294,7 @@ print_operand (file, x, code)
            fprintf (file, "cs");
            break;
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
       case 'C':
@@ -212,7 +310,7 @@ print_operand (file, x, code)
        else
          print_operand (file, x, 0);
        break;
-     
+
       case 'D':
        switch (GET_CODE (x))
          {
@@ -227,7 +325,7 @@ print_operand (file, x, code)
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
@@ -286,7 +384,7 @@ print_operand (file, x, code)
            }
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
@@ -322,10 +420,10 @@ print_operand (file, x, 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:
@@ -343,28 +441,26 @@ print_operand (file, x, code)
            }
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
       case 'A':
        fputc ('(', file);
        if (GET_CODE (XEXP (x, 0)) == REG)
-         output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), GEN_INT (0)));
+         output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx));
        else
          output_address (XEXP (x, 0));
        fputc (')', file);
        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;
 
@@ -422,7 +518,7 @@ print_operand (file, x, code)
            print_operand_address (file, x);
            break;
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
    }
@@ -431,9 +527,7 @@ print_operand (file, x, code)
 /* Output assembly language output for the address ADDR to FILE.  */
 
 void
-print_operand_address (file, addr)
-     FILE *file;
-     rtx addr;
+print_operand_address (FILE *file, rtx addr)
 {
   switch (GET_CODE (addr))
     {
@@ -454,7 +548,7 @@ print_operand_address (file, 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);;
@@ -471,7 +565,7 @@ print_operand_address (file, addr)
 
 /* Count the number of FP registers that have to be saved.  */
 static int
-fp_regs_to_save ()
+fp_regs_to_save (void)
 {
   int i, n = 0;
 
@@ -479,7 +573,7 @@ fp_regs_to_save ()
     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;
@@ -488,13 +582,11 @@ fp_regs_to_save ()
 /* 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,
-   bits 14 to 17 must have the same value. */
+   We assume that the mask already takes that into account.  For instance,
+   bits 14 to 17 must have the same value.  */
 
 void
-mn10300_print_reg_list (file, mask)
-     FILE *file;
-     int mask;
+mn10300_print_reg_list (FILE *file, int mask)
 {
   int need_comma;
   int i;
@@ -513,8 +605,7 @@ mn10300_print_reg_list (file, mask)
 
   if ((mask & 0x3c000) != 0)
     {
-      if ((mask & 0x3c000) != 0x3c000)
-       abort();
+      gcc_assert ((mask & 0x3c000) == 0x3c000);
       if (need_comma)
        fputc (',', file);
       fputs ("exreg1", file);
@@ -525,41 +616,41 @@ mn10300_print_reg_list (file, mask)
 }
 
 int
-can_use_return_insn ()
+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);
 }
 
 /* Returns the set of live, callee-saved registers as a bitmask.  The
    callee-saved extended registers cannot be stored individually, so
-   all of them will be included in the mask if any one of them is used. */
+   all of them will be included in the mask if any one of them is used.  */
 
 int
-mn10300_get_live_callee_saved_regs ()
+mn10300_get_live_callee_saved_regs (void)
 {
   int mask;
   int i;
 
   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;
@@ -587,8 +678,7 @@ mn10300_get_live_callee_saved_regs ()
              (reg:SI R1))) */
 
 void
-mn10300_gen_multiple_store (mask)
-     int mask;
+mn10300_gen_multiple_store (int mask)
 {
   if (mask != 0)
     {
@@ -597,17 +687,17 @@ mn10300_gen_multiple_store (mask)
       rtx par;
       int pari;
 
-      /* Count how many registers need to be saved. */
+      /* Count how many registers need to be saved.  */
       count = 0;
       for (i = 0; i <= LAST_EXTENDED_REGNUM; i++)
        if ((mask & (1 << i)) != 0)
          count += 1;
 
       /* We need one PARALLEL element to update the stack pointer and
-        an additional element for each register that is stored. */
+        an additional element for each register that is stored.  */
       par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
 
-      /* Create the instruction that updates the stack pointer. */
+      /* Create the instruction that updates the stack pointer.  */
       XVECEXP (par, 0, 0)
        = gen_rtx_SET (SImode,
                       stack_pointer_rtx,
@@ -615,7 +705,7 @@ mn10300_gen_multiple_store (mask)
                                     stack_pointer_rtx,
                                     GEN_INT (-count * 4)));
 
-      /* Create each store. */
+      /* Create each store.  */
       pari = 1;
       for (i = LAST_EXTENDED_REGNUM; i >= 0; i--)
        if ((mask & (1 << i)) != 0)
@@ -636,15 +726,15 @@ mn10300_gen_multiple_store (mask)
 }
 
 void
-expand_prologue ()
+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. */
+  /* If we use any of the callee-saved registers, save them now.  */
   mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
 
   if (TARGET_AM33_2 && fp_regs_to_save ())
@@ -689,7 +779,7 @@ expand_prologue ()
 #define SIZE_FMOV_SP(S,N) (SIZE_FMOV_SP_ ((unsigned HOST_WIDE_INT)(S), (N)))
 
       /* Consider alternative save_sp_merge only if we don't need the
-        frame pointer and size is non-zero.  */
+        frame pointer and size is nonzero.  */
       if (! frame_pointer_needed && size)
        {
          /* Insn: add -(size + 4 * num_regs_to_save), sp.  */
@@ -744,10 +834,10 @@ expand_prologue ()
        }
 
       /* Consider alternative save_a0_merge only if we don't need a
-        frame pointer, size is non-zero and the user hasn't
+        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.  */
@@ -770,8 +860,8 @@ expand_prologue ()
        }
 
       /* Consider alternative save_a0_no_merge if the user hasn't
-        changed the calling conventions of a0. */
-      if (call_used_regs[FIRST_ADDRESS_REGNUM]
+        changed the calling conventions of a0.  */
+      if (call_really_used_regs [FIRST_ADDRESS_REGNUM]
          && ! fixed_regs[FIRST_ADDRESS_REGNUM])
        {
          /* Insn: add -4 * num_regs_to_save, sp.  */
@@ -818,17 +908,17 @@ expand_prologue ()
                                 stack_pointer_rtx,
                                 GEN_INT (-(size + 4 * num_regs_to_save))));
          /* We'll have to adjust FP register saves according to the
-            frame size. */
+            frame size.  */
          xsize = size;
          /* Since we've already created the stack frame, don't do it
-            again at the end of the function. */
+            again at the end of the function.  */
          size = 0;
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
-         
+
       /* Now prepare register a0, if we have decided to use it.  */
       switch (strategy)
        {
@@ -846,14 +936,14 @@ expand_prologue ()
            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;
 
@@ -870,7 +960,7 @@ expand_prologue ()
                  }
                else
                  addr = stack_pointer_rtx;
-               
+
                xsize += 4;
              }
 
@@ -890,34 +980,18 @@ expand_prologue ()
     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
-expand_epilogue ()
+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 ())
     {
@@ -971,7 +1045,7 @@ expand_epilogue ()
          /* Insn: fmov (##,sp),fs#, for each fs# to be restored.  */
          this_strategy_size += SIZE_FMOV_SP (0, num_regs_to_save);
          /* We're going to use ret to release the FP registers
-                save area, so, no savings. */
+                save area, so, no savings.  */
 
          if (this_strategy_size < strategy_size)
            {
@@ -994,7 +1068,7 @@ expand_epilogue ()
                                                  - 4 * num_regs_to_save,
                                                  num_regs_to_save);
              /* We're going to use ret to release the FP registers
-                save area, so, no savings. */
+                save area, so, no savings.  */
 
              if (this_strategy_size < strategy_size)
                {
@@ -1005,7 +1079,7 @@ expand_epilogue ()
 
          /* 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.  */
@@ -1055,7 +1129,7 @@ expand_epilogue ()
                                              + 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));
@@ -1064,7 +1138,7 @@ expand_epilogue ()
              break;
 
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
 
@@ -1073,16 +1147,16 @@ expand_epilogue ()
        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)
              {
                /* If we aren't using a post-increment register, use an
-                  SP offset. */
+                  SP offset.  */
                addr = gen_rtx_PLUS (SImode,
                                     stack_pointer_rtx,
                                     GEN_INT (size));
@@ -1113,7 +1187,7 @@ expand_epilogue ()
 
      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.
@@ -1135,10 +1209,10 @@ expand_epilogue ()
     }
 
   /* 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)));
@@ -1149,9 +1223,7 @@ expand_epilogue ()
 /* Update the condition code from the insn.  */
 
 void
-notice_update_cc (body, insn)
-     rtx body;
-     rtx insn;
+notice_update_cc (rtx body, rtx insn)
 {
   switch (get_attr_cc (insn))
     {
@@ -1191,20 +1263,13 @@ notice_update_cc (body, 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 ();
     }
 }
 
@@ -1214,9 +1279,7 @@ notice_update_cc (body, insn)
    registers it saves.  Return 0 otherwise.  */
 
 int
-store_multiple_operation (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   int count;
   int mask;
@@ -1239,7 +1302,7 @@ store_multiple_operation (op, mode)
   /* Check that A is the stack pointer and B is the expected stack size.
      For OP to match, each subsequent instruction should push a word onto
      the stack.  We therefore expect the first instruction to create
-     COUNT-1 stack slots. */
+     COUNT-1 stack slots.  */
   elt = SET_SRC (elt);
   if (GET_CODE (XEXP (elt, 0)) != REG
       || REGNO (XEXP (elt, 0)) != STACK_POINTER_REGNUM
@@ -1253,12 +1316,12 @@ store_multiple_operation (op, mode)
      store a lower-numbered register to the slot below.
 
      LAST keeps track of the smallest-numbered register stored so far.
-     MASK is the set of stored registers. */
+     MASK is the set of stored registers.  */
   last = LAST_EXTENDED_REGNUM + 1;
   mask = 0;
   for (i = 1; i < count; i++)
     {
-      /* Check that element i is a (set (mem M) R) and that R is valid. */
+      /* Check that element i is a (set (mem M) R) and that R is valid.  */
       elt = XVECEXP (op, 0, i);
       if (GET_CODE (elt) != SET
          || GET_CODE (SET_DEST (elt)) != MEM
@@ -1267,7 +1330,7 @@ store_multiple_operation (op, mode)
        return 0;
 
       /* R was OK, so provisionally add it to MASK.  We return 0 in any
-        case if the rest of the instruction has a flaw. */
+        case if the rest of the instruction has a flaw.  */
       last = REGNO (SET_SRC (elt));
       mask |= (1 << last);
 
@@ -1281,7 +1344,7 @@ store_multiple_operation (op, mode)
        return 0;
     }
 
-  /* All or none of the callee-saved extended registers must be in the set. */
+  /* All or none of the callee-saved extended registers must be in the set.  */
   if ((mask & 0x3c000) != 0
       && (mask & 0x3c000) != 0x3c000)
     return 0;
@@ -1289,41 +1352,31 @@ store_multiple_operation (op, mode)
   return mask;
 }
 
-/* Return true if OP is a valid call operand.  */
-
-int
-call_address_operand (op, mode)
-     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 (class, mode, in)
-     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 (class, mode, 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 (class, mode, 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.  */
@@ -1366,17 +1425,16 @@ secondary_reload_class (class, mode, in)
 }
 
 int
-initial_offset (from, to)
-     int from, to;
+initial_offset (int from, int to)
 {
   /* The difference between the argument pointer and the frame pointer
      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
@@ -1390,20 +1448,20 @@ initial_offset (from, 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
@@ -1411,101 +1469,85 @@ initial_offset (from, 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));
+
+  gcc_unreachable ();
+}
 
-  abort ();
+/* Worker function for TARGET_RETURN_IN_MEMORY.  */
+
+static bool
+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
+         || int_size_in_bytes (type) == 0
+         || TYPE_MODE (type) == BLKmode);
 }
 
 /* Flush the argument registers to the stack for a stdarg function;
    return the new argument pointer.  */
-rtx
-mn10300_builtin_saveregs ()
+static rtx
+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
-mn10300_va_start (valist, nextarg)
-     tree valist;
-     rtx nextarg;
+static void
+mn10300_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
   std_expand_builtin_va_start (valist, nextarg);
 }
 
-rtx
-mn10300_va_arg (valist, type)
-     tree valist, 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;
-
-  ptr = build_pointer_type (type);
+/* Return true when a parameter should be passed by reference.  */
 
-  /* "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 (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+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.  */
@@ -1525,38 +1567,35 @@ function_arg (cum, mode, type, named)
   /* 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 (cum, mode, type, named)
-     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;
 
@@ -1588,13 +1627,62 @@ function_arg_partial_nregs (cum, mode, type, named)
       && 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.  */
 const char *
-output_tst (operand, insn)
-     rtx operand, insn;
+output_tst (rtx operand, rtx insn)
 {
   rtx temp;
   int past_call = 0;
@@ -1623,7 +1711,7 @@ output_tst (operand, insn)
          continue;
        }
 
-      /* It must be an insn, see if it is a simple set. */
+      /* It must be an insn, see if it is a simple set.  */
       set = single_set (temp);
       if (!set)
        {
@@ -1632,7 +1720,7 @@ output_tst (operand, 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?
 
@@ -1648,8 +1736,8 @@ output_tst (operand, 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;
@@ -1667,8 +1755,8 @@ output_tst (operand, 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;
@@ -1683,9 +1771,7 @@ output_tst (operand, insn)
 }
 
 int
-impossible_plus_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+impossible_plus_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) != PLUS)
     return 0;
@@ -1697,34 +1783,10 @@ impossible_plus_operand (op, mode)
   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 (op, mode)
-    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 (op, mode)
-    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
-mask_ok_for_mem_btst (len, bit)
-     int len;
-     int bit;
+mask_ok_for_mem_btst (int len, int bit)
 {
   unsigned int mask = 0;
 
@@ -1746,9 +1808,7 @@ mask_ok_for_mem_btst (len, bit)
    expressions will have one of a few well defined forms, so
    we need only check those forms.  */
 int
-symbolic_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+symbolic_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   switch (GET_CODE (op))
     {
@@ -1772,19 +1832,14 @@ symbolic_operand (op, mode)
    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 (x, oldx, mode)
-     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);
@@ -1812,7 +1867,7 @@ legitimize_address (x, oldx, mode)
          regy1 = force_reg (Pmode, force_operand (XEXP (y, 0), 0));
          regy2 = force_reg (Pmode, force_operand (XEXP (y, 1), 0));
          regx1 = force_reg (Pmode,
-                            gen_rtx (GET_CODE (y), Pmode, regx1, regy2));
+                            gen_rtx_fmt_ee (GET_CODE (y), Pmode, regx1, regy2));
          return force_reg (Pmode, gen_rtx_PLUS (Pmode, regx1, regy1));
        }
     }
@@ -1820,11 +1875,9 @@ legitimize_address (x, oldx, mode)
 }
 
 /* Convert a non-PIC address in `orig' to a PIC address using @GOT or
-   @GOTOFF in `reg'. */
+   @GOTOFF in `reg'.  */
 rtx
-legitimize_pic_address (orig, reg)
-     rtx orig;
-     rtx reg;
+legitimize_pic_address (rtx orig, rtx reg)
 {
   if (GET_CODE (orig) == LABEL_REF
       || (GET_CODE (orig) == SYMBOL_REF
@@ -1849,10 +1902,9 @@ legitimize_pic_address (orig, reg)
 }
 
 /* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol
-   isn't protected by a PIC unspec; non-zero otherwise.  */
+   isn't protected by a PIC unspec; nonzero otherwise.  */
 int
-legitimate_pic_operand_p (x)
-     rtx x;
+legitimate_pic_operand_p (rtx x)
 {
   register const char *fmt;
   register int i;
@@ -1864,12 +1916,10 @@ legitimate_pic_operand_p (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--)
     {
@@ -1888,10 +1938,71 @@ legitimate_pic_operand_p (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 (x, unsig)
-     rtx x;
-     int *unsig;
+mn10300_address_cost_1 (rtx x, int *unsig)
 {
   switch (GET_CODE (x))
     {
@@ -1914,7 +2025,7 @@ mn10300_address_cost_1 (x, unsig)
          return 5;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
     case PLUS:
@@ -1928,7 +2039,7 @@ mn10300_address_cost_1 (x, 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;
@@ -1950,44 +2061,27 @@ mn10300_address_cost_1 (x, 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 (x)
-     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 (x, code, outer_code, total)
-     rtx x;
-     int code, 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)))
@@ -2016,6 +2110,12 @@ mn10300_rtx_costs (x, code, outer_code, 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:
@@ -2033,8 +2133,7 @@ mn10300_rtx_costs (x, code, outer_code, total)
    movdf and movdi.  */
 
 bool
-mn10300_wide_const_load_uses_clr (operands)
-     rtx operands[2];
+mn10300_wide_const_load_uses_clr (rtx operands[2])
 {
   long val[2];
 
@@ -2052,7 +2151,7 @@ mn10300_wide_const_load_uses_clr (operands)
        val[1] = INTVAL (high);
       }
       break;
-      
+
     case CONST_DOUBLE:
       if (GET_MODE (operands[1]) == DFmode)
        {
@@ -2068,7 +2167,7 @@ mn10300_wide_const_load_uses_clr (operands)
          val[1] = CONST_DOUBLE_HIGH (operands[1]);
        }
       break;
-      
+
     default:
       return false;
     }
@@ -2079,10 +2178,7 @@ mn10300_wide_const_load_uses_clr (operands)
    may access it using GOTOFF instead of GOT.  */
 
 static void
-mn10300_encode_section_info (decl, rtl, first)
-     tree decl;
-     rtx rtl;
-     int first;
+mn10300_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
 {
   rtx symbol;
 
@@ -2095,3 +2191,106 @@ mn10300_encode_section_info (decl, rtl, first)
   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;
+}