OSDN Git Service

config/m32r/m32r-protos.h: Remove the prototypes for
[pf3gnuchains/gcc-fork.git] / gcc / config / m32r / m32r.c
index 4cf0a3e..dd86186 100644 (file)
@@ -1,25 +1,28 @@
-/* Subroutines used for code generation on the Mitsubishi M32R cpu.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Subroutines used for code generation on the Renesas M32R cpu.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005 Free Software Foundation, Inc.
 
-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
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+   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) any later version.
 
-GNU CC 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.
+   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.  */
+   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.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "regs.h"
@@ -27,7 +30,6 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
@@ -35,7 +37,11 @@ Boston, MA 02111-1307, USA.  */
 #include "function.h"
 #include "recog.h"
 #include "toplev.h"
-#include "m32r-protos.h"
+#include "ggc.h"
+#include "integrate.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
 
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
@@ -52,16 +58,104 @@ enum m32r_model m32r_model;
 const char * m32r_sdata_string = M32R_SDATA_DEFAULT;
 enum m32r_sdata m32r_sdata;
 
-/* Scheduler support */
-int m32r_sched_odd_word_p;
+/* Machine-specific symbol_ref flags.  */
+#define SYMBOL_FLAG_MODEL_SHIFT                SYMBOL_FLAG_MACH_DEP_SHIFT
+#define SYMBOL_REF_MODEL(X) \
+  ((enum m32r_model) ((SYMBOL_REF_FLAGS (X) >> SYMBOL_FLAG_MODEL_SHIFT) & 3))
+
+/* For string literals, etc.  */
+#define LIT_NAME_P(NAME) ((NAME)[0] == '*' && (NAME)[1] == '.')
+
+/* Cache-flush support. Cache-flush is used at trampoline.
+   Default cache-flush is "trap 12".
+    default cache-flush function is "_flush_cache"  (CACHE_FLUSH_FUNC)
+    default cache-flush trap-interrupt number is "12". (CACHE_FLUSH_TRAP)
+   You can change how to generate code of cache-flush with following options.
+   -flush-func=FLUSH-FUNC-NAME
+   -no-flush-func
+   -fluch-trap=TRAP-NUMBER
+   -no-flush-trap.  */
+const char *m32r_cache_flush_func = CACHE_FLUSH_FUNC;
+const char *m32r_cache_flush_trap_string = CACHE_FLUSH_TRAP;
+int m32r_cache_flush_trap = 12;
 
 /* Forward declaration.  */
-static void init_reg_tables                    PARAMS ((void));
-
+static void  init_reg_tables (void);
+static void  block_move_call (rtx, rtx, rtx);
+static int   m32r_is_insn (rtx);
+const struct attribute_spec m32r_attribute_table[];
+static tree  m32r_handle_model_attribute (tree *, tree, tree, int, bool *);
+static void  m32r_output_function_prologue (FILE *, HOST_WIDE_INT);
+static void  m32r_output_function_epilogue (FILE *, HOST_WIDE_INT);
+
+static void  m32r_file_start (void);
+
+static int    m32r_adjust_priority (rtx, int);
+static int    m32r_issue_rate (void);
+
+static void m32r_encode_section_info (tree, rtx, int);
+static bool m32r_in_small_data_p (tree);
+static bool m32r_return_in_memory (tree, tree);
+static void m32r_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+                                        tree, int *, int);
+static void init_idents (void);
+static bool m32r_rtx_costs (rtx, int, int, int *);
+static bool m32r_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+                                   tree, bool);
+static int m32r_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                  tree, bool);
+\f
+/* Initialize the GCC target structure.  */
+#undef  TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE m32r_attribute_table
+
+#undef  TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+#undef  TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+
+#undef  TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE m32r_output_function_prologue
+#undef  TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE m32r_output_function_epilogue
+
+#undef  TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START m32r_file_start
+
+#undef  TARGET_SCHED_ADJUST_PRIORITY
+#define TARGET_SCHED_ADJUST_PRIORITY m32r_adjust_priority
+#undef  TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE m32r_issue_rate
+
+#undef  TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO m32r_encode_section_info
+#undef  TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P m32r_in_small_data_p
+
+#undef  TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS m32r_rtx_costs
+#undef  TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_0
+
+#undef  TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+#undef  TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY m32r_return_in_memory
+#undef  TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS m32r_setup_incoming_varargs
+#undef  TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef  TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE m32r_pass_by_reference
+#undef  TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES m32r_arg_partial_bytes
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 /* Called by OVERRIDE_OPTIONS to initialize various things.  */
 
 void
-m32r_init ()
+m32r_init (void)
 {
   init_reg_tables ();
 
@@ -91,6 +185,15 @@ m32r_init ()
     m32r_sdata = M32R_SDATA_USE;
   else
     error ("bad value (%s) for -msdata switch", m32r_sdata_string);
+
+  if (m32r_cache_flush_trap_string)
+    {
+      /* Change trap-number (12) for cache-flush to the others (0 - 15).  */
+      m32r_cache_flush_trap = atoi (m32r_cache_flush_trap_string);
+      if (m32r_cache_flush_trap < 0 || m32r_cache_flush_trap > 15)
+        error ("bad value (%s) for -flush-trap=n (0=<n<=15)",
+               m32r_cache_flush_trap_string);
+    }
 }
 
 /* Vectors to keep interesting information about registers where it can easily
@@ -126,11 +229,11 @@ enum m32r_mode_class
 
 /* Value is 1 if register/mode pair is acceptable on arc.  */
 
-unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] =
+const unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] =
 {
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
   T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES,
-  S_MODES, C_MODES, A_MODES
+  S_MODES, C_MODES, A_MODES, A_MODES
 };
 
 unsigned int m32r_mode_class [NUM_MACHINE_MODES];
@@ -138,7 +241,7 @@ unsigned int m32r_mode_class [NUM_MACHINE_MODES];
 enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
 
 static void
-init_reg_tables ()
+init_reg_tables (void)
 {
   int i;
 
@@ -174,13 +277,10 @@ init_reg_tables ()
            m32r_mode_class[i] = 0;
          break;
        case MODE_CC:
+         m32r_mode_class[i] = 1 << (int) C_MODE;
+         break;
        default:
-         /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so
-            we must explicitly check for them here.  */
-         if (i == (int) CCmode)
-           m32r_mode_class[i] = 1 << (int) C_MODE;
-         else
-           m32r_mode_class[i] = 0;
+         m32r_mode_class[i] = 0;
          break;
        }
     }
@@ -206,13 +306,8 @@ init_reg_tables ()
        medium: addresses use 32 bits, use bl to make calls
        large: addresses use 32 bits, use seth/add3/jl to make calls
 
-       Grep for MODEL in m32r.h for more info.
-*/
+       Grep for MODEL in m32r.h for more info.  */
 
-static tree interrupt_ident1;
-static tree interrupt_ident2;
-static tree model_ident1;
-static tree model_ident2;
 static tree small_ident1;
 static tree small_ident2;
 static tree medium_ident1;
@@ -221,14 +316,10 @@ static tree large_ident1;
 static tree large_ident2;
 
 static void
-init_idents PARAMS ((void))
+init_idents (void)
 {
-  if (interrupt_ident1 == 0)
+  if (small_ident1 == 0)
     {
-      interrupt_ident1 = get_identifier ("interrupt");
-      interrupt_ident2 = get_identifier ("__interrupt__");
-      model_ident1 = get_identifier ("model");
-      model_ident2 = get_identifier ("__model__");
       small_ident1 = get_identifier ("small");
       small_ident2 = get_identifier ("__small__");
       medium_ident1 = get_identifier ("medium");
@@ -238,237 +329,151 @@ init_idents PARAMS ((void))
     }
 }
 
-/* Return nonzero if IDENTIFIER is a valid decl attribute.  */
-
-int
-m32r_valid_machine_decl_attribute (type, attributes, identifier, args)
-     tree type ATTRIBUTE_UNUSED;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier;
-     tree args;
-{
-  init_idents ();
-
-  if ((identifier == interrupt_ident1
-       || identifier == interrupt_ident2)
-      && list_length (args) == 0)
-    return 1;
-
-  if ((identifier == model_ident1
-       || identifier == model_ident2)
-      && list_length (args) == 1
-      && (TREE_VALUE (args) == small_ident1
-         || TREE_VALUE (args) == small_ident2
-         || TREE_VALUE (args) == medium_ident1
-         || TREE_VALUE (args) == medium_ident2
-         || TREE_VALUE (args) == large_ident1
-         || TREE_VALUE (args) == large_ident2))
-    return 1;
-
-  return 0;
-}
-
-/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible,
-   and two if they are nearly compatible (which causes a warning to be
-   generated).  */
-
-int
-m32r_comp_type_attributes (type1, type2)
-     tree type1 ATTRIBUTE_UNUSED;
-     tree type2 ATTRIBUTE_UNUSED;
+const struct attribute_spec m32r_attribute_table[] =
 {
-  return 1;
-}
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "interrupt", 0, 0, true,  false, false, NULL },
+  { "model",     1, 1, true,  false, false, m32r_handle_model_attribute },
+  { NULL,        0, 0, false, false, false, NULL }
+};
 
-/* Set the default attributes for TYPE.  */
 
-void
-m32r_set_default_type_attributes (type)
-     tree type ATTRIBUTE_UNUSED;
+/* Handle an "model" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+m32r_handle_model_attribute (tree *node ATTRIBUTE_UNUSED, tree name,
+                            tree args, int flags ATTRIBUTE_UNUSED,
+                            bool *no_add_attrs)
 {
-}
-\f
-/* A C statement or statements to switch to the appropriate
-   section for output of DECL.  DECL is either a `VAR_DECL' node
-   or a constant of some sort.  RELOC indicates whether forming
-   the initial value of DECL requires link-time relocations.  */
+  tree arg;
 
-void
-m32r_select_section (decl, reloc)
-     tree decl;
-     int reloc;
-{
-  if (TREE_CODE (decl) == STRING_CST)
-    {
-      if (! flag_writable_strings)
-       const_section ();
-      else
-       data_section ();
-    }
-  else if (TREE_CODE (decl) == VAR_DECL)
+  init_idents ();
+  arg = TREE_VALUE (args);
+
+  if (arg != small_ident1
+      && arg != small_ident2
+      && arg != medium_ident1
+      && arg != medium_ident2
+      && arg != large_ident1
+      && arg != large_ident2)
     {
-      if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0)))
-       sdata_section ();
-      else if ((flag_pic && reloc)
-              || !TREE_READONLY (decl)
-              || TREE_SIDE_EFFECTS (decl)
-              || !DECL_INITIAL (decl)
-              || (DECL_INITIAL (decl) != error_mark_node
-                  && !TREE_CONSTANT (DECL_INITIAL (decl))))
-       data_section ();
-      else
-       const_section ();
+      warning ("invalid argument of %qs attribute",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
-  else
-    const_section ();
-}
 
+  return NULL_TREE;
+}
+\f
 /* Encode section information of DECL, which is either a VAR_DECL,
    FUNCTION_DECL, STRING_CST, CONSTRUCTOR, or ???.
 
    For the M32R we want to record:
 
    - whether the object lives in .sdata/.sbss.
-     objects living in .sdata/.sbss are prefixed with SDATA_FLAG_CHAR
-
    - what code model should be used to access the object
-     small: recorded with no flag - for space efficiency since they'll
-            be the most common
-     medium: prefixed with MEDIUM_FLAG_CHAR
-     large: prefixed with LARGE_FLAG_CHAR
 */
 
-void
-m32r_encode_section_info (decl)
-     tree decl;
+static void
+m32r_encode_section_info (tree decl, rtx rtl, int first)
 {
-  char prefix = 0;
-  tree model = 0;
+  int extra_flags = 0;
+  tree model_attr;
+  enum m32r_model model;
+
+  default_encode_section_info (decl, rtl, first);
+
+  if (!DECL_P (decl))
+    return;
 
-  switch (TREE_CODE (decl))
+  model_attr = lookup_attribute ("model", DECL_ATTRIBUTES (decl));
+  if (model_attr)
     {
-    case VAR_DECL :
-    case FUNCTION_DECL :
-      model = lookup_attribute ("model", DECL_MACHINE_ATTRIBUTES (decl));
-      break;
-    case STRING_CST :
-    case CONSTRUCTOR :
-      /* ??? document all others that can appear here */
-    default :
-      return;
-    }
+      tree id;
 
-  /* Only mark the object as being small data area addressable if
-     it hasn't been explicitly marked with a code model.
+      init_idents ();
 
-     The user can explicitly put an object in the small data area with the
-     section attribute.  If the object is in sdata/sbss and marked with a
-     code model do both [put the object in .sdata and mark it as being
-     addressed with a specific code model - don't mark it as being addressed
-     with an SDA reloc though].  This is ok and might be useful at times.  If
-     the object doesn't fit the linker will give an error.  */
+      id = TREE_VALUE (TREE_VALUE (model_attr));
 
-  if (! model)
+      if (id == small_ident1 || id == small_ident2)
+       model = M32R_MODEL_SMALL;
+      else if (id == medium_ident1 || id == medium_ident2)
+       model = M32R_MODEL_MEDIUM;
+      else if (id == large_ident1 || id == large_ident2)
+       model = M32R_MODEL_LARGE;
+      else
+       abort (); /* shouldn't happen */
+    }
+  else
     {
-      if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
-         && DECL_SECTION_NAME (decl) != NULL_TREE)
-       {
-         char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
-         if (! strcmp (name, ".sdata") || ! strcmp (name, ".sbss"))
-           {
-#if 0 /* ??? There's no reason to disallow this, is there?  */
-             if (TREE_READONLY (decl))
-               error_with_decl (decl, "const objects cannot go in .sdata/.sbss");
-#endif
-             prefix = SDATA_FLAG_CHAR;
-           }
-       }
+      if (TARGET_MODEL_SMALL)
+       model = M32R_MODEL_SMALL;
+      else if (TARGET_MODEL_MEDIUM)
+       model = M32R_MODEL_MEDIUM;
+      else if (TARGET_MODEL_LARGE)
+       model = M32R_MODEL_LARGE;
       else
-       {
-         if (TREE_CODE (decl) == VAR_DECL
-             && ! TREE_READONLY (decl)
-             && ! TARGET_SDATA_NONE)
-           {
-             int size = int_size_in_bytes (TREE_TYPE (decl));
-
-             if (size > 0 && size <= g_switch_value)
-               prefix = SDATA_FLAG_CHAR;
-           }
-       }
+       abort (); /* shouldn't happen */
     }
+  extra_flags |= model << SYMBOL_FLAG_MODEL_SHIFT;
 
-  /* If data area not decided yet, check for a code model.  */
-  if (prefix == 0)
-    {
-      if (model)
-       {
-         tree id;
-         
-         init_idents ();
+  if (extra_flags)
+    SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= extra_flags;
+}
 
-         id = TREE_VALUE (TREE_VALUE (model));
+/* Only mark the object as being small data area addressable if
+   it hasn't been explicitly marked with a code model.
 
-         if (id == small_ident1 || id == small_ident2)
-           ; /* don't mark the symbol specially */
-         else if (id == medium_ident1 || id == medium_ident2)
-           prefix = MEDIUM_FLAG_CHAR;
-         else if (id == large_ident1 || id == large_ident2)
-           prefix = LARGE_FLAG_CHAR;
-         else
-           abort (); /* shouldn't happen */
-       }
-      else
+   The user can explicitly put an object in the small data area with the
+   section attribute.  If the object is in sdata/sbss and marked with a
+   code model do both [put the object in .sdata and mark it as being
+   addressed with a specific code model - don't mark it as being addressed
+   with an SDA reloc though].  This is ok and might be useful at times.  If
+   the object doesn't fit the linker will give an error.  */
+
+static bool
+m32r_in_small_data_p (tree decl)
+{
+  tree section;
+
+  if (TREE_CODE (decl) != VAR_DECL)
+    return false;
+
+  if (lookup_attribute ("model", DECL_ATTRIBUTES (decl)))
+    return false;
+
+  section = DECL_SECTION_NAME (decl);
+  if (section)
+    {
+      char *name = (char *) TREE_STRING_POINTER (section);
+      if (strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0)
+       return true;
+    }
+  else
+    {
+      if (! TREE_READONLY (decl) && ! TARGET_SDATA_NONE)
        {
-         if (TARGET_MODEL_SMALL)
-           ; /* don't mark the symbol specially */
-         else if (TARGET_MODEL_MEDIUM)
-           prefix = MEDIUM_FLAG_CHAR;
-         else if (TARGET_MODEL_LARGE)
-           prefix = LARGE_FLAG_CHAR;
-         else
-           abort (); /* shouldn't happen */
+         int size = int_size_in_bytes (TREE_TYPE (decl));
+
+         if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
+           return true;
        }
     }
 
-  if (prefix != 0)
-    {
-      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
-                 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
-      const char *str = XSTR (XEXP (rtl, 0), 0);
-      int len = strlen (str);
-      char *newstr = ggc_alloc (len + 2);
-      strcpy (newstr + 1, str);
-      *newstr = prefix;
-      XSTR (XEXP (rtl, 0), 0) = newstr;
-    }
+  return false;
 }
 
 /* Do anything needed before RTL is emitted for each function.  */
 
 void
-m32r_init_expanders ()
+m32r_init_expanders (void)
 {
   /* ??? At one point there was code here.  The function is left in
      to make it easy to experiment.  */
 }
 \f
-/* Acceptable arguments to the call insn.  */
-
 int
-call_address_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return symbolic_operand (op, mode);
-
-/* Constants and values in registers are not OK, because
-   the m32r BL instruction can only support PC relative branching.  */ 
-}
-
-int
-call_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+call_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) != MEM)
     return 0;
@@ -476,44 +481,23 @@ call_operand (op, mode)
   return call_address_operand (op, mode);
 }
 
-/* Returns 1 if OP is a symbol reference.  */
-
-int
-symbolic_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF:
-    case LABEL_REF:
-    case CONST :
-      return 1;
-
-    default:
-      return 0;
-    }
-}
-
 /* Return 1 if OP is a reference to an object in .sdata/.sbss.  */
 
 int
-small_data_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+small_data_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (! TARGET_SDATA_USE)
     return 0;
 
   if (GET_CODE (op) == SYMBOL_REF)
-    return SDATA_NAME_P (XSTR (op, 0));
+    return SYMBOL_REF_SMALL_P (op);
 
   if (GET_CODE (op) == CONST
       && GET_CODE (XEXP (op, 0)) == PLUS
       && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
       && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
       && INT16_P (INTVAL (XEXP (XEXP (op, 0), 1))))
-    return SDATA_NAME_P (XSTR (XEXP (XEXP (op, 0), 0), 0));
+    return SYMBOL_REF_SMALL_P (XEXP (XEXP (op, 0), 0));
 
   return 0;
 }
@@ -521,324 +505,75 @@ small_data_operand (op, mode)
 /* Return 1 if OP is a symbol that can use 24 bit addressing.  */
 
 int
-addr24_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+addr24_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  if (GET_CODE (op) == LABEL_REF)
-    return TARGET_ADDR24;
-
-  if (GET_CODE (op) == SYMBOL_REF)
-    return (SMALL_NAME_P (XSTR (op, 0))
-           || (TARGET_ADDR24
-               && (CONSTANT_POOL_ADDRESS_P (op)
-                   || LIT_NAME_P (XSTR (op, 0)))));
+  rtx sym;
 
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
-      && UINT24_P (INTVAL (XEXP (XEXP (op, 0), 1))))
-    {
-      rtx sym = XEXP (XEXP (op, 0), 0);
-      return (SMALL_NAME_P (XSTR (sym, 0))
-             || (TARGET_ADDR24
-                 && (CONSTANT_POOL_ADDRESS_P (op)
-                     || LIT_NAME_P (XSTR (op, 0)))));
-    }
-
-  return 0;
-}
-
-/* Return 1 if OP is a symbol that needs 32 bit addressing.  */
+  if (flag_pic)
+    return 0;
 
-int
-addr32_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
   if (GET_CODE (op) == LABEL_REF)
-    return TARGET_ADDR32;
-
-  if (GET_CODE (op) == SYMBOL_REF)
-    return (! addr24_operand (op, mode)
-           && ! small_data_operand (op, mode));
-
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
-    {
-      return (! addr24_operand (op, mode)
-             && ! small_data_operand (op, mode));
-    }
-
-  return 0;
-}
-
-/* Return 1 if OP is a function that can be called with the `bl' insn.  */
+    return TARGET_ADDR24;
 
-int
-call26_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
   if (GET_CODE (op) == SYMBOL_REF)
-    return ! LARGE_NAME_P (XSTR (op, 0));
-
-  return TARGET_CALL26;
-}
-
-/* Returns 1 if OP is an acceptable operand for seth/add3.  */
+    sym = op;
+  else if (GET_CODE (op) == CONST
+          && GET_CODE (XEXP (op, 0)) == PLUS
+          && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
+          && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
+          && UINT24_P (INTVAL (XEXP (XEXP (op, 0), 1))))
+    sym = XEXP (XEXP (op, 0), 0);
+  else
+    return 0;
 
-int
-seth_add3_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) == SYMBOL_REF
-      || GET_CODE (op) == LABEL_REF)
+  if (SYMBOL_REF_MODEL (sym) == M32R_MODEL_SMALL)
     return 1;
 
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
-      && INT16_P (INTVAL (XEXP (XEXP (op, 0), 1))))
+  if (TARGET_ADDR24
+      && (CONSTANT_POOL_ADDRESS_P (sym)
+         || LIT_NAME_P (XSTR (sym, 0))))
     return 1;
 
   return 0;
 }
 
-/* Return true if OP is a signed 8 bit immediate value.  */
-
-int
-int8_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return INT8_P (INTVAL (op));
-}
-
-/* Return true if OP is a signed 16 bit immediate value
-   useful in comparisons.  */
-
-int
-cmp_int16_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return CMP_INT16_P (INTVAL (op));
-}
-
-/* Return true if OP is an unsigned 16 bit immediate value.  */
-
-int
-uint16_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return UINT16_P (INTVAL (op));
-}
-
-/* Return true if OP is a register or signed 16 bit value.  */
-
-int
-reg_or_int16_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
-    return register_operand (op, mode);
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return INT16_P (INTVAL (op));
-}
-
-/* Return true if OP is a register or an unsigned 16 bit value.  */
-
-int
-reg_or_uint16_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
-    return register_operand (op, mode);
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return UINT16_P (INTVAL (op));
-}
-
-/* Return true if OP is a register or an integer value that can be
-   used is SEQ/SNE.  We can use either XOR of the value or ADD of
-   the negative of the value for the constant.  Don't allow 0,
-   because that is special cased.  */
+/* Return 1 if OP is a symbol that needs 32 bit addressing.  */
 
 int
-reg_or_eq_int16_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+addr32_operand (rtx op, enum machine_mode mode)
 {
-  HOST_WIDE_INT value;
-
-  if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
-    return register_operand (op, mode);
-
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
+  rtx sym;
 
-  value = INTVAL (op);
-  return (value != 0) && (UINT16_P (value) || CMP_INT16_P (-value));
-}
-
-/* Return true if OP is a register or signed 16 bit value for compares.  */
+  if (GET_CODE (op) == LABEL_REF)
+    return TARGET_ADDR32;
 
-int
-reg_or_cmp_int16_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (GET_CODE (op) == REG || GET_CODE (op) == SUBREG)
-    return register_operand (op, mode);
-  if (GET_CODE (op) != CONST_INT)
+  if (GET_CODE (op) == SYMBOL_REF)
+    sym = op;
+  else if (GET_CODE (op) == CONST
+          && GET_CODE (XEXP (op, 0)) == PLUS
+          && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
+          && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
+          && ! flag_pic)
+    sym = XEXP (XEXP (op, 0), 0);
+  else
     return 0;
-  return CMP_INT16_P (INTVAL (op));
-}
 
-/* Return true if OP is a const_int requiring two instructions to load.  */
-
-int
-two_insn_const_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  if (INT16_P (INTVAL (op))
-      || UINT24_P (INTVAL (op))
-      || UPPER16_P (INTVAL (op)))
-    return 0;
-  return 1;
+  return (! addr24_operand (sym, mode)
+         && ! small_data_operand (sym, mode));
 }
 
-/* Return true if OP is an acceptable argument for a single word
-   move source.  */
-
-int
-move_src_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF :
-    case CONST :
-      return addr24_operand (op, mode);
-    case CONST_INT :
-      /* ??? We allow more cse opportunities if we only allow constants
-        loadable with one insn, and split the rest into two.  The instances
-        where this would help should be rare and the current way is
-        simpler.  */
-      return INT32_P (INTVAL (op));
-    case LABEL_REF :
-      return TARGET_ADDR24;
-    case CONST_DOUBLE :
-      if (mode == SFmode)
-       return 1;
-      else if (mode == SImode)
-       {
-         /* Large unsigned constants are represented as const_double's.  */
-         unsigned HOST_WIDE_INT low, high;
-
-         low = CONST_DOUBLE_LOW (op);
-         high = CONST_DOUBLE_HIGH (op);
-         return high == 0 && low <= 0xffffffff;
-       }
-      else
-       return 0;
-    case REG :
-      return register_operand (op, mode);
-    case SUBREG :
-      /* (subreg (mem ...) ...) can occur here if the inner part was once a
-        pseudo-reg and is now a stack slot.  */
-      if (GET_CODE (SUBREG_REG (op)) == MEM)
-       return address_operand (XEXP (SUBREG_REG (op), 0), mode);
-      else
-       return register_operand (op, mode);
-    case MEM :
-      if (GET_CODE (XEXP (op, 0)) == PRE_INC
-         || GET_CODE (XEXP (op, 0)) == PRE_DEC)
-       return 0;               /* loads can't do pre-{inc,dec} */
-      return address_operand (XEXP (op, 0), mode);
-    default :
-      return 0;
-    }
-}
-
-/* Return true if OP is an acceptable argument for a double word
-   move source.  */
+/* Return 1 if OP is a function that can be called with the `bl' insn.  */
 
 int
-move_double_src_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+call26_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  switch (GET_CODE (op))
-    {
-    case CONST_INT :
-    case CONST_DOUBLE :
-      return 1;
-    case REG :
-      return register_operand (op, mode);
-    case SUBREG :
-      /* (subreg (mem ...) ...) can occur here if the inner part was once a
-        pseudo-reg and is now a stack slot.  */
-      if (GET_CODE (SUBREG_REG (op)) == MEM)
-       return move_double_src_operand (SUBREG_REG (op), mode);
-      else
-       return register_operand (op, mode);
-    case MEM :
-      /* Disallow auto inc/dec for now.  */
-      if (GET_CODE (XEXP (op, 0)) == PRE_DEC
-         || GET_CODE (XEXP (op, 0)) == PRE_INC)
-       return 0;
-      return address_operand (XEXP (op, 0), mode);
-    default :
-      return 0;
-    }
-}
+  if (flag_pic)
+    return 1;
 
-/* Return true if OP is an acceptable argument for a move destination.  */
+  if (GET_CODE (op) == SYMBOL_REF)
+    return SYMBOL_REF_MODEL (op) != M32R_MODEL_LARGE;
 
-int
-move_dest_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  switch (GET_CODE (op))
-    {
-    case REG :
-      return register_operand (op, mode);
-    case SUBREG :
-      /* (subreg (mem ...) ...) can occur here if the inner part was once a
-        pseudo-reg and is now a stack slot.  */
-      if (GET_CODE (SUBREG_REG (op)) == MEM)
-       return address_operand (XEXP (SUBREG_REG (op), 0), mode);
-      else
-       return register_operand (op, mode);
-    case MEM :
-      if (GET_CODE (XEXP (op, 0)) == POST_INC)
-       return 0;               /* stores can't do post inc */
-      return address_operand (XEXP (op, 0), mode);
-    default :
-      return 0;
-    }
+  return TARGET_CALL26;
 }
 
 /* Return 1 if OP is a DImode const we want to handle inline.
@@ -846,8 +581,7 @@ move_dest_operand (op, mode)
    It is used by the 'G' CONST_DOUBLE_OK_FOR_LETTER.  */
 
 int
-easy_di_const (op)
-     rtx op;
+easy_di_const (rtx op)
 {
   rtx high_rtx, low_rtx;
   HOST_WIDE_INT high, low;
@@ -867,8 +601,7 @@ easy_di_const (op)
    It is used by the 'H' CONST_DOUBLE_OK_FOR_LETTER.  */
 
 int
-easy_df_const (op)
-     rtx op;
+easy_df_const (rtx op)
 {
   REAL_VALUE_TYPE r;
   long l[2];
@@ -882,133 +615,45 @@ easy_df_const (op)
   return 0;
 }
 
-/* Return 1 if OP is an EQ or NE comparison operator.  */
-
-int
-eqne_comparison_operator (op, mode)
-    rtx op;
-    enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  enum rtx_code code = GET_CODE (op);
-
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
-  return (code == EQ || code == NE);
-}
-
-/* Return 1 if OP is a signed comparison operator.  */
-
-int
-signed_comparison_operator (op, mode)
-    rtx op;
-    enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  enum rtx_code code = GET_CODE (op);
-
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
-  return (code == EQ || code == NE
-         || code == LT || code == LE || code == GT || code == GE);
-}
-
-/* Return 1 if OP is (mem (reg ...)).
-   This is used in insn length calcs.  */
-
-int
-memreg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG;
-}
-
-/* Return true if OP is an acceptable input argument for a zero/sign extend
-   operation.  */
-
-int
-extend_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  rtx addr;
-
-  switch (GET_CODE (op))
-    {
-    case REG :
-    case SUBREG :
-      return register_operand (op, mode);
-
-    case MEM :
-      addr = XEXP (op, 0);
-      if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
-       return 0;               /* loads can't do pre inc/pre dec */
-
-      return address_operand (addr, mode);
-
-    default :
-      return 0;
-    }
-}
-
-/* Return non-zero if the operand is an insn that is a small insn.
-   Allow const_int 0 as well, which is a placeholder for NOP slots.  */
+/* Return 1 if OP is (mem (reg ...)).
+   This is used in insn length calcs.  */
 
 int
-small_insn_p (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+memreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  if (GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
-    return 1;
-
-  if (! INSN_P (op))
-    return 0;
-
-  return get_attr_length (op) == 2;
+  return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == REG;
 }
 
-/* Return non-zero if the operand is an insn that is a large insn.  */
+/* Return nonzero if TYPE must be passed by indirect reference.  */
 
-int
-large_insn_p (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+static bool
+m32r_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
+                       enum machine_mode mode, tree type,
+                       bool named ATTRIBUTE_UNUSED)
 {
-  if (! INSN_P (op))
-    return 0;
+  int size;
 
-  return get_attr_length (op) != 2;
-}
+  if (type)
+    size = int_size_in_bytes (type);
+  else
+    size = GET_MODE_SIZE (mode);
 
+  return (size < 0 || size > 8);
+}
 \f
 /* Comparisons.  */
 
-/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
-   return the mode to be used for the comparison.  */
-
-int
-m32r_select_cc_mode (op, x, y)
-     int op ATTRIBUTE_UNUSED;
-     rtx x ATTRIBUTE_UNUSED;
-     rtx y ATTRIBUTE_UNUSED;
-{
-  return (int) CCmode;
-}
-
 /* X and Y are two things to compare using CODE.  Emit the compare insn and
    return the rtx for compare [arg0 of the if_then_else].
    If need_compare is true then the comparison insn must be generated, rather
-   than being susummed into the following branch instruction.  */
+   than being subsumed into the following branch instruction.  */
 
 rtx
-gen_compare (code, x, y, need_compare)
-     enum rtx_code code;
-     rtx x, y;
-     int need_compare;
+gen_compare (enum rtx_code code, rtx x, rtx y, int need_compare)
 {
-  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
-  enum rtx_code compare_code, branch_code;
-  rtx cc_reg = gen_rtx_REG (mode, CARRY_REGNUM);
+  enum rtx_code compare_code;
+  enum rtx_code branch_code;
+  rtx cc_reg = gen_rtx_REG (CCmode, CARRY_REGNUM);
   int must_swap = 0;
 
   switch (code)
@@ -1034,27 +679,27 @@ gen_compare (code, x, y, need_compare)
        {
        case EQ:
          if (GET_CODE (y) == CONST_INT
-             && CMP_INT16_P (INTVAL (y))               /* reg equal to small const.  */
+             && CMP_INT16_P (INTVAL (y))               /* Reg equal to small const.  */
              && y != const0_rtx)
            {
              rtx tmp = gen_reg_rtx (SImode);           
              
-             emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y));
+             emit_insn (gen_addsi3 (tmp, x, GEN_INT (-INTVAL (y))));
              x = tmp;
              y = const0_rtx;
            }
-         else if (CONSTANT_P (y))                      /* reg equal to const.  */
+         else if (CONSTANT_P (y))                      /* Reg equal to const.  */
            {
              rtx tmp = force_reg (GET_MODE (x), y);
              y = tmp;
            }
 
-         if (register_operand (y, SImode)              /* reg equal to reg.  */
-             || y == const0_rtx)                       /* req equal to zero. */
+         if (register_operand (y, SImode)              /* Reg equal to reg.  */
+             || y == const0_rtx)                       /* Reg equal to zero.  */
            {
              emit_insn (gen_cmp_eqsi_insn (x, y));
                
-             return gen_rtx (code, mode, cc_reg, const0_rtx);
+             return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
            }
          break;
       
@@ -1062,7 +707,7 @@ gen_compare (code, x, y, need_compare)
          if (register_operand (y, SImode)
              || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
            {
-             rtx tmp = gen_reg_rtx (SImode);         /* reg compared to reg. */
+             rtx tmp = gen_reg_rtx (SImode);         /* Reg compared to reg.  */
              
              switch (code)
                {
@@ -1074,15 +719,15 @@ gen_compare (code, x, y, need_compare)
                  if (y == const0_rtx)
                    tmp = const1_rtx;
                  else
-                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                   emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
                  emit_insn (gen_cmp_ltsi_insn (x, tmp));
                  code = EQ;
                  break;
                case GT:
                  if (GET_CODE (y) == CONST_INT)
-                   tmp = gen_rtx (PLUS, SImode, y, const1_rtx);
+                   tmp = gen_rtx_PLUS (SImode, y, const1_rtx);
                  else
-                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                   emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
                  emit_insn (gen_cmp_ltsi_insn (x, tmp));
                  code = NE;
                  break;
@@ -1094,7 +739,7 @@ gen_compare (code, x, y, need_compare)
                  abort ();
                }
              
-             return gen_rtx (code, mode, cc_reg, const0_rtx);
+             return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
            }
          break;
          
@@ -1102,7 +747,7 @@ gen_compare (code, x, y, need_compare)
          if (register_operand (y, SImode)
              || (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
            {
-             rtx tmp = gen_reg_rtx (SImode);         /* reg (unsigned) compared to reg. */
+             rtx tmp = gen_reg_rtx (SImode);         /* Reg (unsigned) compared to reg.  */
              
              switch (code)
                {
@@ -1114,15 +759,15 @@ gen_compare (code, x, y, need_compare)
                  if (y == const0_rtx)
                    tmp = const1_rtx;
                  else
-                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                   emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
                  emit_insn (gen_cmp_ltusi_insn (x, tmp));
                  code = EQ;
                  break;
                case GTU:
                  if (GET_CODE (y) == CONST_INT)
-                   tmp = gen_rtx (PLUS, SImode, y, const1_rtx);
+                   tmp = gen_rtx_PLUS (SImode, y, const1_rtx);
                  else
-                   emit_insn (gen_cmp_ne_small_const_insn (tmp, y, const1_rtx));
+                   emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
                  emit_insn (gen_cmp_ltusi_insn (x, tmp));
                  code = NE;
                  break;
@@ -1134,7 +779,7 @@ gen_compare (code, x, y, need_compare)
                  abort();
                }
              
-             return gen_rtx (code, mode, cc_reg, const0_rtx);
+             return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
            }
          break;
 
@@ -1144,32 +789,34 @@ gen_compare (code, x, y, need_compare)
     }
   else
     {
-      /* reg/reg equal comparison */
+      /* Reg/reg equal comparison.  */
       if (compare_code == EQ
          && register_operand (y, SImode))
-       return gen_rtx (code, mode, x, y);
+       return gen_rtx_fmt_ee (code, CCmode, x, y);
       
-      /* reg/zero signed comparison */
+      /* Reg/zero signed comparison.  */
       if ((compare_code == EQ || compare_code == LT)
          && y == const0_rtx)
-       return gen_rtx (code, mode, x, y);
+       return gen_rtx_fmt_ee (code, CCmode, x, y);
       
-      /* reg/smallconst equal comparison */
+      /* Reg/smallconst equal comparison.  */
       if (compare_code == EQ
          && GET_CODE (y) == CONST_INT
          && CMP_INT16_P (INTVAL (y)))
        {
          rtx tmp = gen_reg_rtx (SImode);
-         emit_insn (gen_cmp_ne_small_const_insn (tmp, x, y));
-         return gen_rtx (code, mode, tmp, const0_rtx);
+
+         emit_insn (gen_addsi3 (tmp, x, GEN_INT (-INTVAL (y))));
+         return gen_rtx_fmt_ee (code, CCmode, tmp, const0_rtx);
        }
       
-      /* reg/const equal comparison */
+      /* Reg/const equal comparison.  */
       if (compare_code == EQ
          && CONSTANT_P (y))
        {
          rtx tmp = force_reg (GET_MODE (x), y);
-         return gen_rtx (code, mode, x, tmp);
+
+         return gen_rtx_fmt_ee (code, CCmode, x, tmp);
        }
     }
 
@@ -1179,11 +826,8 @@ gen_compare (code, x, y, need_compare)
        y = force_reg (GET_MODE (x), y);
       else
        {
-         int ok_const =
-           (code == LTU || code == LEU || code == GTU || code == GEU)
-           ? uint16_operand (y, GET_MODE (y))
-           : reg_or_cmp_int16_operand (y, GET_MODE (y));
-         
+         int ok_const = reg_or_int16_operand (y, GET_MODE (y));
+
          if (! ok_const)
            y = force_reg (GET_MODE (x), y);
        }
@@ -1205,14 +849,13 @@ gen_compare (code, x, y, need_compare)
       abort ();
     }
 
-  return gen_rtx (branch_code, VOIDmode, cc_reg, CONST0_RTX (mode));
+  return gen_rtx_fmt_ee (branch_code, VOIDmode, cc_reg, CONST0_RTX (CCmode));
 }
 \f
 /* Split a 2 word move (DI or DF) into component parts.  */
 
 rtx
-gen_split_move_double (operands)
-     rtx operands[];
+gen_split_move_double (rtx operands[])
 {
   enum machine_mode mode = GET_MODE (operands[0]);
   rtx dest = operands[0];
@@ -1223,16 +866,16 @@ gen_split_move_double (operands)
      subregs to make this code simpler.  It is safe to call
      alter_subreg any time after reload.  */
   if (GET_CODE (dest) == SUBREG)
-    dest = alter_subreg (dest);
+    alter_subreg (&dest);
   if (GET_CODE (src) == SUBREG)
-    src = alter_subreg (src);
+    alter_subreg (&src);
 
   start_sequence ();
   if (GET_CODE (dest) == REG)
     {
       int dregno = REGNO (dest);
 
-      /* reg = reg */
+      /* Reg = reg.  */
       if (GET_CODE (src) == REG)
        {
          int sregno = REGNO (src);
@@ -1251,7 +894,7 @@ gen_split_move_double (operands)
                                  operand_subword (src,  !reverse, TRUE, mode)));
        }
 
-      /* reg = constant */
+      /* Reg = constant.  */
       else if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
        {
          rtx words[2];
@@ -1265,20 +908,20 @@ gen_split_move_double (operands)
                                  words[1]));
        }
 
-      /* reg = mem */
+      /* Reg = mem.  */
       else if (GET_CODE (src) == MEM)
        {
          /* If the high-address word is used in the address, we must load it
             last.  Otherwise, load it first.  */
-         rtx addr = XEXP (src, 0);
-         int reverse = (refers_to_regno_p (dregno, dregno+1, addr, 0) != 0);
+         int reverse
+           = (refers_to_regno_p (dregno, dregno + 1, XEXP (src, 0), 0) != 0);
 
          /* We used to optimize loads from single registers as
 
                ld r1,r3+; ld r2,r3
 
             if r3 were not used subsequently.  However, the REG_NOTES aren't
-            propigated correctly by the reload phase, and it can cause bad
+            propagated correctly by the reload phase, and it can cause bad
             code to be generated.  We could still try:
 
                ld r1,r3+; ld r2,r3; addi r3,-4
@@ -1286,28 +929,25 @@ gen_split_move_double (operands)
             which saves 2 bytes and doesn't force longword alignment.  */
          emit_insn (gen_rtx_SET (VOIDmode,
                                  operand_subword (dest, reverse, TRUE, mode),
-                                 change_address (src, SImode,
-                                                 plus_constant (addr,
-                                                                reverse * UNITS_PER_WORD))));
+                                 adjust_address (src, SImode,
+                                                 reverse * UNITS_PER_WORD)));
 
          emit_insn (gen_rtx_SET (VOIDmode,
                                  operand_subword (dest, !reverse, TRUE, mode),
-                                 change_address (src, SImode,
-                                                 plus_constant (addr,
-                                                                (!reverse) * UNITS_PER_WORD))));
+                                 adjust_address (src, SImode,
+                                                 !reverse * UNITS_PER_WORD)));
        }
-
       else
        abort ();
     }
 
-  /* mem = reg */
+  /* Mem = reg.  */
   /* We used to optimize loads from single registers as
 
        st r1,r3; st r2,+r3
 
      if r3 were not used subsequently.  However, the REG_NOTES aren't
-     propigated correctly by the reload phase, and it can cause bad
+     propagated correctly by the reload phase, and it can cause bad
      code to be generated.  We could still try:
 
        st r1,r3; st r2,+r3; addi r3,-4
@@ -1315,49 +955,51 @@ gen_split_move_double (operands)
      which saves 2 bytes and doesn't force longword alignment.  */
   else if (GET_CODE (dest) == MEM && GET_CODE (src) == REG)
     {
-      rtx addr = XEXP (dest, 0);
-
       emit_insn (gen_rtx_SET (VOIDmode,
-                             change_address (dest, SImode, addr),
+                             adjust_address (dest, SImode, 0),
                              operand_subword (src, 0, TRUE, mode)));
 
       emit_insn (gen_rtx_SET (VOIDmode,
-                             change_address (dest, SImode,
-                                             plus_constant (addr, UNITS_PER_WORD)),
+                             adjust_address (dest, SImode, UNITS_PER_WORD),
                              operand_subword (src, 1, TRUE, mode)));
     }
 
   else
     abort ();
 
-  val = gen_sequence ();
+  val = get_insns ();
   end_sequence ();
   return val;
 }
 
 \f
-/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro.  */
-
-int
-function_arg_partial_nregs (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+static int
+m32r_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                       tree type, bool named ATTRIBUTE_UNUSED)
 {
-  int ret;
-  int size = (((mode == BLKmode && type)
-              ? int_size_in_bytes (type)
-              : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  int words;
+  unsigned int size =
+    (((mode == BLKmode && type)
+      ? (unsigned int) int_size_in_bytes (type)
+      : GET_MODE_SIZE (mode)) + UNITS_PER_WORD - 1)
+    / UNITS_PER_WORD;
 
   if (*cum >= M32R_MAX_PARM_REGS)
-    ret = 0;
+    words = 0;
   else if (*cum + size > M32R_MAX_PARM_REGS)
-    ret = (*cum + size) - M32R_MAX_PARM_REGS;
+    words = (*cum + size) - M32R_MAX_PARM_REGS;
   else
-    ret = 0;
+    words = 0;
+
+  return words * UNITS_PER_WORD;
+}
 
-  return ret;
+/* Worker function for TARGET_RETURN_IN_MEMORY.  */
+
+static bool
+m32r_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+  return m32r_pass_by_reference (NULL, TYPE_MODE (type), type, false);
 }
 
 /* Do any needed setup for a variadic function.  For the M32R, we must
@@ -1367,13 +1009,9 @@ function_arg_partial_nregs (cum, mode, type, named)
    CUM has not been updated for the last named argument which has type TYPE
    and mode MODE, and we rely on this fact.  */
 
-void
-m32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
-     CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int *pretend_size;
-     int no_rtl;
+static void
+m32r_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                            tree type, int *pretend_size, int no_rtl)
 {
   int first_anon_arg;
 
@@ -1384,12 +1022,8 @@ m32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
   if (mode == BLKmode)
     abort ();
 
-  /* We must treat `__builtin_va_alist' as an anonymous arg.  */
-  if (current_function_varargs)
-    first_anon_arg = *cum;
-  else
-    first_anon_arg = (ROUND_ADVANCE_CUM (*cum, mode, type)
-                     + ROUND_ADVANCE_ARG (mode, type));
+  first_anon_arg = (ROUND_ADVANCE_CUM (*cum, mode, type)
+                   + ROUND_ADVANCE_ARG (mode, type));
 
   if (first_anon_arg < M32R_MAX_PARM_REGS)
     {
@@ -1402,93 +1036,18 @@ m32r_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
       regblock = gen_rtx_MEM (BLKmode,
                              plus_constant (arg_pointer_rtx,
                                             FIRST_PARM_OFFSET (0)));
-      MEM_ALIAS_SET (regblock) = get_varargs_alias_set ();
-      move_block_from_reg (first_reg_offset, regblock,
-                          size, size * UNITS_PER_WORD);
+      set_mem_alias_set (regblock, get_varargs_alias_set ());
+      move_block_from_reg (first_reg_offset, regblock, size);
 
       *pretend_size = (size * UNITS_PER_WORD);
     }
 }
 
 \f
-/* Implement `va_arg'.  */
-
-rtx
-m32r_va_arg (valist, type)
-     tree valist, type;
-{
-  HOST_WIDE_INT size, rsize;
-  tree t;
-  rtx addr_rtx;
-
-  size = int_size_in_bytes (type);
-  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-
-  if (size > 8)
-    {
-      tree type_ptr, type_ptr_ptr;
-
-      /* Pass by reference.  */
-
-      type_ptr = build_pointer_type (type);
-      type_ptr_ptr = build_pointer_type (type_ptr);
-
-      t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, 
-                build_int_2 (UNITS_PER_WORD, 0));
-      TREE_SIDE_EFFECTS (t) = 1;
-      t = build1 (NOP_EXPR, type_ptr_ptr, t);
-      TREE_SIDE_EFFECTS (t) = 1;
-      t = build1 (INDIRECT_REF, type_ptr, t);
-
-      addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
-    }
-  else
-    {
-      /* Pass by value.  */
-
-      if (size < UNITS_PER_WORD)
-       {
-         /* Care for bigendian correction on the aligned address.  */
-         t = build (PLUS_EXPR, ptr_type_node, valist,
-                    build_int_2 (rsize - size, 0));
-         addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
-         addr_rtx = copy_to_reg (addr_rtx);
-
-         /* Increment AP.  */
-         t = build (PLUS_EXPR, va_list_type_node, valist,
-                    build_int_2 (rsize, 0));
-         t = build (MODIFY_EXPR, va_list_type_node, valist, t);
-         TREE_SIDE_EFFECTS (t) = 1;
-         expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-       }
-      else
-       {
-         t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, 
-                    build_int_2 (rsize, 0));
-         TREE_SIDE_EFFECTS (t) = 1;
-         addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
-       }
-    }
-
-  return addr_rtx;
-}
-\f
-int
-m32r_adjust_cost (insn, link, dep_insn, cost)
-     rtx insn ATTRIBUTE_UNUSED;
-     rtx link ATTRIBUTE_UNUSED;
-     rtx dep_insn ATTRIBUTE_UNUSED;
-     int cost;
-{
-  return cost;
-}
-
-\f
 /* Return true if INSN is real instruction bearing insn.  */
 
 static int
-m32r_is_insn (insn)
-     rtx insn;
+m32r_is_insn (rtx insn)
 {
   return (INSN_P (insn)
          && GET_CODE (PATTERN (insn)) != USE
@@ -1499,10 +1058,8 @@ m32r_is_insn (insn)
 /* Increase the priority of long instructions so that the
    short instructions are scheduled ahead of the long ones.  */
 
-int
-m32r_adjust_priority (insn, priority)
-     rtx insn;
-     int priority;
+static int
+m32r_adjust_priority (rtx insn, int priority)
 {
   if (m32r_is_insn (insn)
       && get_attr_insn_size (insn) != INSN_SIZE_SHORT)
@@ -1512,186 +1069,66 @@ m32r_adjust_priority (insn, priority)
 }
 
 \f
-/* Initialize for scheduling a group of instructions.  */
+/* Indicate how many instructions can be issued at the same time.
+   This is sort of a lie.  The m32r can issue only 1 long insn at
+   once, but it can issue 2 short insns.  The default therefore is
+   set at 2, but this can be overridden by the command line option
+   -missue-rate=1.  */
 
-void
-m32r_sched_init (stream, verbose)
-     FILE * stream ATTRIBUTE_UNUSED;
-     int verbose ATTRIBUTE_UNUSED;
+static int
+m32r_issue_rate (void)
 {
-  m32r_sched_odd_word_p = FALSE;
+  return ((TARGET_LOW_ISSUE_RATE) ? 1 : 2);
 }
-
 \f
-/* Reorder the schedulers priority list if needed */
+/* Cost functions.  */
 
-void
-m32r_sched_reorder (stream, verbose, ready, n_ready)
-     FILE * stream;
-     int verbose;
-     rtx * ready;
-     int n_ready;
+static bool
+m32r_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
 {
-  if (TARGET_DEBUG)
-    return;
-
-  if (verbose <= 7)
-    stream = (FILE *)0;
-
-  if (stream)
-    fprintf (stream,
-            ";;\t\t::: Looking at %d insn(s) on ready list, boundary is %s word\n",
-            n_ready,
-            (m32r_sched_odd_word_p) ? "odd" : "even");
-
-  if (n_ready > 1)
+  switch (code)
     {
-      rtx * long_head = (rtx *) alloca (sizeof (rtx) * n_ready);
-      rtx * long_tail = long_head;
-      rtx * short_head = (rtx *) alloca (sizeof (rtx) * n_ready);
-      rtx * short_tail = short_head;
-      rtx * new_head = (rtx *) alloca (sizeof (rtx) * n_ready);
-      rtx * new_tail = new_head + (n_ready - 1);
-      int   i;
-
-      /* Loop through the instructions, classifing them as short/long.  Try
-        to keep 2 short together and/or 1 long.  Note, the ready list is
-        actually ordered backwards, so keep it in that manner.  */
-      for (i = n_ready-1; i >= 0; i--)
+      /* Small integers are as cheap as registers.  4 byte values can be
+         fetched as immediate constants - let's give that the cost of an
+         extra insn.  */
+    case CONST_INT:
+      if (INT16_P (INTVAL (x)))
        {
-         rtx insn = ready[i];
-         enum rtx_code code;
-
-         if (! m32r_is_insn (insn))
-           {
-             /* Dump all current short/long insns just in case.  */
-             while (long_head != long_tail)
-               *new_tail-- = *long_head++;
-
-             while (short_head != short_tail)
-               *new_tail-- = *short_head++;
-
-             *new_tail-- = insn;
-             if (stream)
-               fprintf (stream,
-                        ";;\t\t::: Skipping non instruction %d\n",
-                        INSN_UID (insn));
-
-           }
-
-         else
-           {
-             if (get_attr_insn_size (insn) != INSN_SIZE_SHORT)
-               *long_tail++ = insn;
-
-             else
-               *short_tail++ = insn;
-           }
+         *total = 0;
+         return true;
        }
+      /* FALLTHRU */
 
-      /* If we are on an odd word, emit a single short instruction if
-        we can */
-      if (m32r_sched_odd_word_p && short_head != short_tail)
-       *new_tail-- = *short_head++;
-
-      /* Now dump out all of the long instructions */
-      while (long_head != long_tail)
-       *new_tail-- = *long_head++;
-
-      /* Now dump out all of the short instructions */
-      while (short_head != short_tail)
-       *new_tail-- = *short_head++;
-
-      if (new_tail+1 != new_head)
-       abort ();
-
-      memcpy (ready, new_head, sizeof (rtx) * n_ready);
-      if (stream)
-       {
-#ifdef HAIFA
-         fprintf (stream, ";;\t\t::: New ready list:               ");
-         debug_ready_list (ready, n_ready);
-#else
-         int i;
-         for (i = 0; i < n_ready; i++)
-           {
-             rtx insn = ready[i];
-             enum rtx_code code;
-
-             fprintf (stream, " %d", INSN_UID (ready[i]));
-
-             if (! m32r_is_insn (insn))
-               fputs ("(?)", stream);
-
-             else if (get_attr_insn_size (insn) != INSN_SIZE_SHORT)
-               fputs ("(l)", stream);
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = COSTS_N_INSNS (1);
+      return true;
 
-             else
-               fputs ("(s)", stream);
-           }
+    case CONST_DOUBLE:
+      {
+       rtx high, low;
 
-         fprintf (stream, "\n");
-#endif
-       }
-    }
-}
+       split_double (x, &high, &low);
+       *total = COSTS_N_INSNS (!INT16_P (INTVAL (high))
+                               + !INT16_P (INTVAL (low)));
+       return true;
+      }
 
-\f
-/* If we have a machine that can issue a variable # of instructions
-   per cycle, indicate how many more instructions can be issued
-   after the current one.  */
-int
-m32r_sched_variable_issue (stream, verbose, insn, how_many)
-     FILE * stream;
-     int verbose;
-     rtx insn;
-     int how_many;
-{
-  int orig_odd_word_p = m32r_sched_odd_word_p;
-  int short_p = FALSE;
+    case MULT:
+      *total = COSTS_N_INSNS (3);
+      return true;
 
-  how_many--;
-  if (how_many > 0 && !TARGET_DEBUG)
-    {
-      if (! m32r_is_insn (insn))
-       how_many++;
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      *total = COSTS_N_INSNS (10);
+      return true;
 
-      else if (get_attr_insn_size (insn) != INSN_SIZE_SHORT)
-       {
-         how_many = 0;
-         m32r_sched_odd_word_p = 0;
-       }
-      else
-       {
-         m32r_sched_odd_word_p = !m32r_sched_odd_word_p;
-         short_p = TRUE;
-       }
+    default:
+      return false;
     }
-
-  if (verbose > 7 && stream)
-    fprintf (stream,
-            ";;\t\t::: %s insn %d starts on an %s word, can emit %d more instruction(s)\n",
-            short_p ? "short" : "long",
-            INSN_UID (insn),
-            orig_odd_word_p ? "odd" : "even",
-            how_many);
-
-  return how_many;
-}
-\f
-/* Cost functions.  */
-
-/* Provide the costs of an addressing mode that contains ADDR.
-   If ADDR is not a valid address, its cost is irrelevant.
-
-   This function is trivial at the moment.  This code doesn't live
-   in m32r.h so it's easy to experiment.  */
-
-int
-m32r_address_cost (addr)
-     rtx addr ATTRIBUTE_UNUSED;
-{
-  return 1;
 }
 \f
 /* Type of function DECL.
@@ -1700,8 +1137,7 @@ m32r_address_cost (addr)
    call with DECL = NULL_TREE.  */
 
 enum m32r_function_type
-m32r_compute_function_type (decl)
-     tree decl;
+m32r_compute_function_type (tree decl)
 {
   /* Cached value.  */
   static enum m32r_function_type fn_type = M32R_FUNCTION_UNKNOWN;
@@ -1720,7 +1156,7 @@ m32r_compute_function_type (decl)
     return fn_type;
 
   /* Compute function type.  */
-  fn_type = (lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (current_function_decl)) != NULL_TREE
+  fn_type = (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE
             ? M32R_FUNCTION_INTERRUPT
             : M32R_FUNCTION_NORMAL);
 
@@ -1774,23 +1210,22 @@ Notes:
    containing anonymous args separately but that complicates things too
    much (so it's not done).
 3) The return address is saved after the register save area so as to have as
-   many insns as possible between the restoration of `lr' and the `jmp lr'.
-*/
+   many insns as possible between the restoration of `lr' and the `jmp lr'.  */
 
 /* Structure to be filled in by m32r_compute_frame_size with register
    save masks, and offsets for the current function.  */
 struct m32r_frame_info
 {
-  unsigned int total_size;     /* # bytes that the entire frame takes up */
-  unsigned int extra_size;     /* # bytes of extra stuff */
-  unsigned int pretend_size;   /* # bytes we push and pretend caller did */
-  unsigned int args_size;      /* # bytes that outgoing arguments take up */
-  unsigned int reg_size;       /* # bytes needed to store regs */
-  unsigned int var_size;       /* # bytes that variables take up */
-  unsigned int gmask;          /* mask of saved gp registers */
-  unsigned int save_fp;                /* nonzero if fp must be saved */
-  unsigned int save_lr;                /* nonzero if lr (return addr) must be saved */
-  int          initialized;    /* nonzero if frame size already calculated */
+  unsigned int total_size;     /* # bytes that the entire frame takes up */
+  unsigned int extra_size;     /* # bytes of extra stuff */
+  unsigned int pretend_size;   /* # bytes we push and pretend caller did */
+  unsigned int args_size;      /* # bytes that outgoing arguments take up */
+  unsigned int reg_size;       /* # bytes needed to store regs */
+  unsigned int var_size;       /* # bytes that variables take up */
+  unsigned int gmask;          /* Mask of saved gp registers.  */
+  unsigned int save_fp;                /* Nonzero if fp must be saved.  */
+  unsigned int save_lr;                /* Nonzero if lr (return addr) must be saved.  */
+  int          initialized;    /* Nonzero if frame size already calculated.  */
 };
 
 /* Current frame information calculated by m32r_compute_frame_size.  */
@@ -1800,20 +1235,20 @@ static struct m32r_frame_info current_frame_info;
 static struct m32r_frame_info zero_frame_info;
 
 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
+#define RETURN_ADDR_MASK   (1 << (RETURN_ADDR_REGNUM))
 
 /* Tell prologue and epilogue if register REGNO should be saved / restored.
    The return address and frame pointer are treated separately.
    Don't consider them here.  */
 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
-((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
&& (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p)))
+  ((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
 && (regs_ever_live[regno] && (!call_really_used_regs[regno] || interrupt_p)))
 
 #define MUST_SAVE_FRAME_POINTER (regs_ever_live[FRAME_POINTER_REGNUM])
-#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM] || profile_flag)
+#define MUST_SAVE_RETURN_ADDR   (regs_ever_live[RETURN_ADDR_REGNUM] || current_function_profile)
 
-#define SHORT_INSN_SIZE 2      /* size of small instructions */
-#define LONG_INSN_SIZE 4       /* size of long instructions */
+#define SHORT_INSN_SIZE 2      /* Size of small instructions.  */
+#define LONG_INSN_SIZE 4       /* Size of long instructions.  */
 
 /* Return the bytes needed to compute the frame pointer from the current
    stack pointer.
@@ -1821,8 +1256,7 @@ static struct m32r_frame_info zero_frame_info;
    SIZE is the size needed for local variables.  */
 
 unsigned int
-m32r_compute_frame_size (size)
-     int size;                 /* # of var. bytes allocated.  */
+m32r_compute_frame_size (int size)     /* # of var. bytes allocated.  */
 {
   int regno;
   unsigned int total_size, var_size, args_size, pretend_size, extra_size;
@@ -1830,6 +1264,7 @@ m32r_compute_frame_size (size)
   unsigned int gmask;
   enum m32r_function_type fn_type;
   int interrupt_p;
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table);
 
   var_size     = M32R_STACK_ALIGN (size);
   args_size    = M32R_STACK_ALIGN (current_function_outgoing_args_size);
@@ -1845,10 +1280,10 @@ m32r_compute_frame_size (size)
   interrupt_p = M32R_INTERRUPT_P (fn_type);
 
   /* Calculate space needed for registers.  */
-
   for (regno = 0; regno < M32R_MAX_INT_REGS; regno++)
     {
-      if (MUST_SAVE_REGISTER (regno, interrupt_p))
+      if (MUST_SAVE_REGISTER (regno, interrupt_p)
+          || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
        {
          reg_size += UNITS_PER_WORD;
          gmask |= 1 << regno;
@@ -1856,7 +1291,7 @@ m32r_compute_frame_size (size)
     }
 
   current_frame_info.save_fp = MUST_SAVE_FRAME_POINTER;
-  current_frame_info.save_lr = MUST_SAVE_RETURN_ADDR;
+  current_frame_info.save_lr = MUST_SAVE_RETURN_ADDR || pic_reg_used;
 
   reg_size += ((current_frame_info.save_fp + current_frame_info.save_lr)
               * UNITS_PER_WORD);
@@ -1882,27 +1317,53 @@ m32r_compute_frame_size (size)
   return total_size;
 }
 \f
-/* When the `length' insn attribute is used, this macro specifies the
-   value to be assigned to the address of the first insn in a
-   function.  If not specified, 0 is used.  */
-
-int
-m32r_first_insn_address ()
+/* The table we use to reference PIC data.  */
+static rtx global_offset_table;
+                                                                                
+static void
+m32r_reload_lr (rtx sp, int size)
 {
-  if (! current_frame_info.initialized)
-    m32r_compute_frame_size (get_frame_size ());
+  rtx lr = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
 
-  return 0;
+  if (size == 0)
+    emit_insn (gen_movsi (lr, gen_rtx_MEM (Pmode, sp)));
+  else if (size <= 32768)
+    emit_insn (gen_movsi (lr, gen_rtx_MEM (Pmode,
+                                          gen_rtx_PLUS (Pmode, sp,
+                                                        GEN_INT (size)))));
+  else
+    {   
+      rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
+
+      emit_insn (gen_movsi (tmp, GEN_INT (size)));
+      emit_insn (gen_addsi3 (tmp, tmp, sp));
+      emit_insn (gen_movsi (lr, gen_rtx_MEM (Pmode, tmp)));
+    }
+
+  emit_insn (gen_rtx_USE (VOIDmode, lr));
 }
-\f
+
+void
+m32r_load_pic_register (void)
+{
+  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
+                         GEN_INT (TARGET_MODEL_SMALL)));
+                                                                                
+  /* Need to emit this whether or not we obey regdecls,
+     since setjmp/longjmp can cause life info to screw up.  */
+  emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+}
+
 /* Expand the m32r prologue as a series of insns.  */
 
 void
-m32r_expand_prologue ()
+m32r_expand_prologue (void)
 {
   int regno;
   int frame_size;
   unsigned int gmask;
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table);
 
   if (! current_frame_info.initialized)
     m32r_compute_frame_size (get_frame_size ());
@@ -1925,7 +1386,6 @@ m32r_expand_prologue ()
     }
 
   /* Save any registers we need to and set up fp.  */
-
   if (current_frame_info.save_fp)
     emit_insn (gen_movsi_push (stack_pointer_rtx, frame_pointer_rtx));
 
@@ -1950,13 +1410,14 @@ m32r_expand_prologue ()
                   + current_frame_info.reg_size));
 
   if (frame_size == 0)
-    ; /* nothing to do */
+    ; /* Nothing to do.  */
   else if (frame_size <= 32768)
     emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
                           GEN_INT (-frame_size)));
   else
     {
       rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
+
       emit_insn (gen_movsi (tmp, GEN_INT (frame_size)));
       emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
     }
@@ -1964,7 +1425,19 @@ m32r_expand_prologue ()
   if (frame_pointer_needed)
     emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
 
-  if (profile_flag || profile_block_flag)
+  if (current_function_profile)
+    /* Push lr for mcount (form_pc, x).  */
+    emit_insn (gen_movsi_push (stack_pointer_rtx,
+                               gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM)));
+                                                                                
+  if (pic_reg_used)
+    {
+      m32r_load_pic_register ();
+      m32r_reload_lr (stack_pointer_rtx,
+                      (current_function_profile ? 0 : frame_size));
+    }
+
+  if (current_function_profile && !pic_reg_used)
     emit_insn (gen_blockage ());
 }
 
@@ -1973,19 +1446,14 @@ m32r_expand_prologue ()
    Note, if this is changed, you need to mirror the changes in
    m32r_compute_frame_size which calculates the prolog size.  */
 
-void
-m32r_output_function_prologue (file, size)
-     FILE * file;
-     int    size;
+static void
+m32r_output_function_prologue (FILE * file, HOST_WIDE_INT size)
 {
   enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl);
 
   /* If this is an interrupt handler, mark it as such.  */
   if (M32R_INTERRUPT_P (fn_type))
-    {
-      fprintf (file, "\t%s interrupt handler\n",
-              ASM_COMMENT_START);
-    }
+    fprintf (file, "\t%s interrupt handler\n", ASM_COMMENT_START);
 
   if (! current_frame_info.initialized)
     m32r_compute_frame_size (size);
@@ -2001,12 +1469,10 @@ m32r_output_function_prologue (file, size)
 }
 \f
 /* Do any necessary cleanup after a function to restore stack, frame,
-   and regs. */
+   and regs.  */
 
-void
-m32r_output_function_epilogue (file, size)
-     FILE * file;
-     int    size ATTRIBUTE_UNUSED;
+static void
+m32r_output_function_epilogue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
   int regno;
   int noepilogue = FALSE;
@@ -2047,7 +1513,7 @@ m32r_output_function_epilogue (file, size)
        {
          unsigned int reg_offset = var_size + args_size;
          if (reg_offset == 0)
-           ; /* nothing to do */
+           ; /* Nothing to do.  */
          else if (reg_offset < 128)
            fprintf (file, "\taddi %s,%s%d\n",
                     sp_str, IMMEDIATE_PREFIX, reg_offset);
@@ -2063,6 +1529,7 @@ m32r_output_function_epilogue (file, size)
       else if (frame_pointer_needed)
        {
          unsigned int reg_offset = var_size + args_size;
+
          if (reg_offset == 0)
            fprintf (file, "\tmv %s,%s\n", sp_str, fp_str);
          else if (reg_offset < 32768)
@@ -2103,21 +1570,16 @@ m32r_output_function_epilogue (file, size)
        fprintf (file, "\tjmp %s\n", reg_names[RETURN_ADDR_REGNUM]);
     }
 
-#if 0 /* no longer needed */
-  /* Ensure the function cleanly ends on a 32 bit boundary.  */
-  fprintf (file, "\t.fillinsn\n");
-#endif
-
   /* Reset state info for each function.  */
   current_frame_info = zero_frame_info;
   m32r_compute_function_type (NULL_TREE);
 }
 \f
-/* Return non-zero if this function is known to have a null or 1 instruction
+/* Return nonzero if this function is known to have a null or 1 instruction
    epilogue.  */
 
 int
-direct_return ()
+direct_return (void)
 {
   if (!reload_completed)
     return FALSE;
@@ -2125,18 +1587,129 @@ direct_return ()
   if (! current_frame_info.initialized)
     m32r_compute_frame_size (get_frame_size ());
 
-  return current_frame_info.total_size == 0;
+   return current_frame_info.total_size == 0;
 }
 
 \f
-/* PIC */
+/* PIC.  */
+
+int
+m32r_legitimate_pic_operand_p (rtx x)
+{
+  if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
+    return 0;
+                                                                                
+  if (GET_CODE (x) == CONST
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+          || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
+      && (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
+    return 0;
+                                                                                
+  return 1;
+}
+
+rtx
+m32r_legitimize_pic_address (rtx orig, rtx reg)
+{
+#ifdef DEBUG_PIC
+  printf("m32r_legitimize_pic_address()\n");
+#endif
+
+  if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
+    {
+      rtx pic_ref, address;
+      rtx insn;
+      int subregs = 0;
+
+      if (reg == 0)
+        {
+          if (reload_in_progress || reload_completed)
+            abort ();
+          else
+            reg = gen_reg_rtx (Pmode);
+
+          subregs = 1;
+        }
+
+      if (subregs)
+        address = gen_reg_rtx (Pmode);
+      else
+        address = reg;
+
+      current_function_uses_pic_offset_table = 1;
+
+      if (GET_CODE (orig) == LABEL_REF
+          || (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (orig)))
+        {
+          emit_insn (gen_gotoff_load_addr (reg, orig));
+          emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
+          return reg;
+        }
+
+      emit_insn (gen_pic_load_addr (address, orig));
+
+      emit_insn (gen_addsi3 (address, address, pic_offset_table_rtx));
+      pic_ref = gen_const_mem (Pmode, address);
+      insn = emit_move_insn (reg, pic_ref);
+#if 0
+      /* Put a REG_EQUAL note on this insn, so that it can be optimized
+         by loop.  */
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
+                  REG_NOTES (insn));
+#endif
+      return reg;
+    }
+  else if (GET_CODE (orig) == CONST)
+    {
+      rtx base, offset;
+
+      if (GET_CODE (XEXP (orig, 0)) == PLUS
+          && XEXP (XEXP (orig, 0), 1) == pic_offset_table_rtx)
+        return orig;
+
+      if (reg == 0)
+        {
+          if (reload_in_progress || reload_completed)
+            abort ();
+          else
+            reg = gen_reg_rtx (Pmode);
+        }
+
+      if (GET_CODE (XEXP (orig, 0)) == PLUS)
+        {
+          base = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
+          if (base == reg)
+            offset = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), NULL_RTX);
+          else
+            offset = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), reg);
+        }
+      else
+        return orig;
+
+      if (GET_CODE (offset) == CONST_INT)
+        {
+          if (INT16_P (INTVAL (offset)))
+            return plus_constant (base, INTVAL (offset));
+          else if (! reload_in_progress && ! reload_completed)
+            offset = force_reg (Pmode, offset);
+          else
+            /* If we reach here, then something is seriously wrong.  */
+            abort ();
+        }
+
+      return gen_rtx_PLUS (Pmode, base, offset);
+    }
+
+  return orig;
+}
 
 /* Emit special PIC prologues and epilogues.  */
 
 void
-m32r_finalize_pic ()
+m32r_finalize_pic (void)
 {
-  /* nothing to do */
+  current_function_uses_pic_offset_table |= current_function_profile;
 }
 \f
 /* Nested function support.  */
@@ -2146,23 +1719,24 @@ m32r_finalize_pic ()
    CXT is an RTX for the static chain value for the function.  */
 
 void
-m32r_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp ATTRIBUTE_UNUSED;
-     rtx fnaddr ATTRIBUTE_UNUSED;
-     rtx cxt ATTRIBUTE_UNUSED;
+m32r_initialize_trampoline (rtx tramp ATTRIBUTE_UNUSED,
+                           rtx fnaddr ATTRIBUTE_UNUSED,
+                           rtx cxt ATTRIBUTE_UNUSED)
 {
 }
 \f
-/* Set the cpu type and print out other fancy things,
-   at the top of the file.  */
-
-void
-m32r_asm_file_start (file)
-     FILE * file;
+static void
+m32r_file_start (void)
 {
+  default_file_start ();
+
   if (flag_verbose_asm)
-    fprintf (file, "%s M32R/D special options: -G %d\n",
+    fprintf (asm_out_file,
+            "%s M32R/D special options: -G " HOST_WIDE_INT_PRINT_UNSIGNED "\n",
             ASM_COMMENT_START, g_switch_value);
+
+  if (TARGET_LITTLE_ENDIAN)
+    fprintf (asm_out_file, "\t.little\n");
 }
 \f
 /* Print operand X (an rtx) in assembler syntax to file FILE.
@@ -2170,10 +1744,7 @@ m32r_asm_file_start (file)
    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
 
 void
-m32r_print_operand (file, x, code)
-     FILE * file;
-     rtx    x;
-     int    code;
+m32r_print_operand (FILE * file, rtx x, int code)
 {
   rtx addr;
 
@@ -2185,14 +1756,14 @@ m32r_print_operand (file, x, code)
       if (GET_CODE (x) == REG)
        fprintf (file, "@+%s", reg_names [REGNO (x)]);
       else
-       output_operand_lossage ("invalid operand to %s code");
+       output_operand_lossage ("invalid operand to %%s code");
       return;
       
     case 'p':
       if (GET_CODE (x) == REG)
        fprintf (file, "@%s+", reg_names [REGNO (x)]);
       else
-       output_operand_lossage ("invalid operand to %p code");
+       output_operand_lossage ("invalid operand to %%p code");
       return;
 
     case 'R' :
@@ -2215,14 +1786,14 @@ m32r_print_operand (file, x, code)
          fputc (')', file);
        }
       else
-       output_operand_lossage ("invalid operand to %R code");
+       output_operand_lossage ("invalid operand to %%R code");
       return;
 
-    case 'H' : /* High word */
-    case 'L' : /* Low word */
+    case 'H' : /* High word */
+    case 'L' : /* Low word */
       if (GET_CODE (x) == REG)
        {
-         /* L = least significant word, H = most significant word */
+         /* L = least significant word, H = most significant word */
          if ((WORDS_BIG_ENDIAN != 0) ^ (code == 'L'))
            fputs (reg_names[REGNO (x)], file);
          else
@@ -2238,25 +1809,24 @@ m32r_print_operand (file, x, code)
                   code == 'L' ? INTVAL (first) : INTVAL (second));
        }
       else
-       output_operand_lossage ("invalid operand to %H/%L code");
+       output_operand_lossage ("invalid operand to %%H/%%L code");
       return;
 
     case 'A' :
       {
-       REAL_VALUE_TYPE d;
        char str[30];
 
        if (GET_CODE (x) != CONST_DOUBLE
            || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
-         fatal_insn ("Bad insn for 'A'", x);
-       REAL_VALUE_FROM_CONST_DOUBLE (d, x);
-       REAL_VALUE_TO_DECIMAL (d, "%.20e", str);
+         fatal_insn ("bad insn for 'A'", x);
+
+       real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1);
        fprintf (file, "%s", str);
        return;
       }
 
-    case 'B' : /* Bottom half */
-    case 'T' : /* Top half */
+    case 'B' : /* Bottom half */
+    case 'T' : /* Top half */
       /* Output the argument to a `seth' insn (sets the Top half-word).
         For constants output arguments to a seth/or3 pair to set Top and
         Bottom halves.  For symbols output arguments to a seth/add3 pair to
@@ -2272,12 +1842,7 @@ m32r_print_operand (file, x, code)
 
            split_double (x, &first, &second);
            x = WORDS_BIG_ENDIAN ? second : first;
-           fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-                    "0x%x",
-#else
-                    "0x%lx",
-#endif
+           fprintf (file, HOST_WIDE_INT_PRINT_HEX,
                     (code == 'B'
                      ? INTVAL (x) & 0xffff
                      : (INTVAL (x) >> 16) & 0xffff));
@@ -2300,7 +1865,7 @@ m32r_print_operand (file, x, code)
          fputc (')', file);
          return;
        default :
-         output_operand_lossage ("invalid operand to %T/%B code");
+         output_operand_lossage ("invalid operand to %%T/%%B code");
          return;
        }
       break;
@@ -2315,7 +1880,7 @@ m32r_print_operand (file, x, code)
            fputs (".a", file);
        }
       else
-       output_operand_lossage ("invalid operand to %U code");
+       output_operand_lossage ("invalid operand to %%U code");
       return;
 
     case 'N' :
@@ -2323,31 +1888,19 @@ m32r_print_operand (file, x, code)
       if (GET_CODE (x) == CONST_INT)
        output_addr_const (file, GEN_INT (- INTVAL (x)));
       else
-       output_operand_lossage ("invalid operand to %N code");
+       output_operand_lossage ("invalid operand to %%N code");
       return;
 
     case 'X' :
       /* Print a const_int in hex.  Used in comments.  */
       if (GET_CODE (x) == CONST_INT)
-       fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-                "0x%x",
-#else
-                "0x%lx",
-#endif
-                INTVAL (x));
+       fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
       return;
 
     case '#' :
       fputs (IMMEDIATE_PREFIX, file);
       return;
 
-#if 0 /* ??? no longer used */
-    case '@' :
-      fputs (reg_names[SDA_REGNUM], file);
-      return;
-#endif
-
     case 0 :
       /* Do nothing special.  */
       break;
@@ -2368,21 +1921,21 @@ m32r_print_operand (file, x, code)
       if (GET_CODE (addr) == PRE_INC)
        {
          if (GET_CODE (XEXP (addr, 0)) != REG)
-           fatal_insn ("Pre-increment address is not a register", x);
+           fatal_insn ("pre-increment address is not a register", x);
 
          fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]);
        }
       else if (GET_CODE (addr) == PRE_DEC)
        {
          if (GET_CODE (XEXP (addr, 0)) != REG)
-           fatal_insn ("Pre-decrement address is not a register", x);
+           fatal_insn ("pre-decrement address is not a register", x);
 
          fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]);
        }
       else if (GET_CODE (addr) == POST_INC)
        {
          if (GET_CODE (XEXP (addr, 0)) != REG)
-           fatal_insn ("Post-increment address is not a register", x);
+           fatal_insn ("post-increment address is not a register", x);
 
          fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]);
        }
@@ -2418,13 +1971,11 @@ m32r_print_operand (file, x, code)
 /* Print a memory address as an operand to reference that memory location.  */
 
 void
-m32r_print_operand_address (file, addr)
-     FILE * file;
-     rtx    addr;
+m32r_print_operand_address (FILE * file, rtx addr)
 {
-  register rtx base;
-  register rtx index = 0;
-  int          offset = 0;
+  rtx base;
+  rtx index = 0;
+  int offset = 0;
 
   switch (GET_CODE (addr))
     {
@@ -2460,7 +2011,7 @@ m32r_print_operand_address (file, addr)
              fputs (reg_names[REGNO (base)], file);
            }
          else
-           fatal_insn ("Bad address", addr);
+           fatal_insn ("bad address", addr);
        }
       else if (GET_CODE (base) == LO_SUM)
        {
@@ -2476,12 +2027,12 @@ m32r_print_operand_address (file, addr)
          fputs (reg_names[REGNO (XEXP (base, 0))], file);
        }
       else
-       fatal_insn ("Bad address", addr);
+       fatal_insn ("bad address", addr);
       break;
 
     case LO_SUM :
       if (GET_CODE (XEXP (addr, 0)) != REG)
-       fatal_insn ("Lo_sum not of register", addr);
+       fatal_insn ("lo_sum not of register", addr);
       if (small_data_operand (XEXP (addr, 1), VOIDmode))
        fputs ("sda(", file);
       else
@@ -2491,15 +2042,15 @@ m32r_print_operand_address (file, addr)
       fputs (reg_names[REGNO (XEXP (addr, 0))], file);
       break;
 
-    case PRE_INC :     /* Assume SImode */
+    case PRE_INC :     /* Assume SImode */
       fprintf (file, "+%s", reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
-    case PRE_DEC :     /* Assume SImode */
+    case PRE_DEC :     /* Assume SImode */
       fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
-    case POST_INC :    /* Assume SImode */
+    case POST_INC :    /* Assume SImode */
       fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
@@ -2510,10 +2061,9 @@ m32r_print_operand_address (file, addr)
 }
 
 /* Return true if the operands are the constants 0 and 1.  */
+
 int
-zero_and_one (operand1, operand2)
-     rtx operand1;
-     rtx operand2;
+zero_and_one (rtx operand1, rtx operand2)
 {
   return
        GET_CODE (operand1) == CONST_INT
@@ -2522,70 +2072,14 @@ zero_and_one (operand1, operand2)
        ||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0)));
 }
 
-/* Return non-zero if the operand is suitable for use in a conditional move sequence.  */
-int
-conditional_move_operand (operand, mode)
-     rtx operand;
-     enum machine_mode mode;
-{
-  /* Only defined for simple integers so far... */
-  if (mode != SImode && mode != HImode && mode != QImode)
-    return FALSE;
-
-  /* At the moment we can hanndle moving registers and loading constants.  */
-  /* To be added: Addition/subtraction/bitops/multiplication of registers.  */
-
-  switch (GET_CODE (operand))
-    {
-    case REG:
-      return 1;
-
-    case CONST_INT:
-      return INT8_P (INTVAL (operand));
-
-    default:
-#if 0
-      fprintf (stderr, "Test for cond move op of type: %s\n",
-              GET_RTX_NAME (GET_CODE (operand)));
-#endif
-      return 0;
-    }
-}
-
-/* Return true if the code is a test of the carry bit */
-int
-carry_compare_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  rtx x;
-
-  if (GET_MODE (op) != CCmode && GET_MODE (op) != VOIDmode)
-    return FALSE;
-
-  if (GET_CODE (op) != NE && GET_CODE (op) != EQ)
-    return FALSE;
-
-  x = XEXP (op, 0);
-  if (GET_CODE (x) != REG || REGNO (x) != CARRY_REGNUM)
-    return FALSE;
-
-  x = XEXP (op, 1);
-  if (GET_CODE (x) != CONST_INT || INTVAL (x) != 0)
-    return FALSE;
-
-  return TRUE;
-}
-
 /* Generate the correct assembler code to handle the conditional loading of a
    value into a register.  It is known that the operands satisfy the
    conditional_move_operand() function above.  The destination is operand[0].
    The condition is operand [1].  The 'true' value is operand [2] and the
    'false' value is operand [3].  */
+
 char *
-emit_cond_move (operands, insn)
-     rtx * operands;
-     rtx   insn ATTRIBUTE_UNUSED;
+emit_cond_move (rtx * operands, rtx insn ATTRIBUTE_UNUSED)
 {
   static char buffer [100];
   const char * dest = reg_names [REGNO (operands [0])];
@@ -2609,21 +2103,20 @@ emit_cond_move (operands, insn)
     }
 
   sprintf (buffer, "mvfc %s, cbr", dest);
-  
+
   /* If the true value was '0' then we need to invert the results of the move.  */
   if (INTVAL (operands [2]) == 0)
     sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1",
             dest, dest);
-  
+
   return buffer;
 }
 
 /* Returns true if the registers contained in the two
-   rtl expressions are different. */
+   rtl expressions are different.  */
+
 int
-m32r_not_same_reg (a, b)
-     rtx a;
-     rtx b;
+m32r_not_same_reg (rtx a, rtx b)
 {
   int reg_a = -1;
   int reg_b = -2;
@@ -2644,12 +2137,33 @@ m32r_not_same_reg (a, b)
 }
 
 \f
+rtx
+m32r_function_symbol (const char *name)
+{
+  int extra_flags = 0;
+  enum m32r_model model;
+  rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
+
+  if (TARGET_MODEL_SMALL)
+    model = M32R_MODEL_SMALL;
+  else if (TARGET_MODEL_MEDIUM)
+    model = M32R_MODEL_MEDIUM;
+  else if (TARGET_MODEL_LARGE)
+    model = M32R_MODEL_LARGE;
+  else
+    abort (); /* Shouldn't happen.  */
+  extra_flags |= model << SYMBOL_FLAG_MODEL_SHIFT;
+                                                                                
+  if (extra_flags)
+    SYMBOL_REF_FLAGS (sym) |= extra_flags;
+
+  return sym;
+}
+
 /* Use a library function to move some bytes.  */
+
 static void
-block_move_call (dest_reg, src_reg, bytes_rtx)
-     rtx dest_reg;
-     rtx src_reg;
-     rtx bytes_rtx;
+block_move_call (rtx dest_reg, rtx src_reg, rtx bytes_rtx)
 {
   /* We want to pass the size as Pmode, which will normally be SImode
      but will be DImode if we are using 64 bit longs and pointers.  */
@@ -2657,28 +2171,13 @@ block_move_call (dest_reg, src_reg, bytes_rtx)
       && GET_MODE (bytes_rtx) != Pmode)
     bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);
 
-#ifdef TARGET_MEM_FUNCTIONS
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "memcpy"), 0,
+  emit_library_call (m32r_function_symbol ("memcpy"), 0,
                     VOIDmode, 3, dest_reg, Pmode, src_reg, Pmode,
                     convert_to_mode (TYPE_MODE (sizetype), bytes_rtx,
-                                     TREE_UNSIGNED (sizetype)),
+                                     TYPE_UNSIGNED (sizetype)),
                     TYPE_MODE (sizetype));
-#else
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "bcopy"), 0,
-                    VOIDmode, 3, src_reg, Pmode, dest_reg, Pmode,
-                    convert_to_mode (TYPE_MODE (integer_type_node), bytes_rtx,
-                                     TREE_UNSIGNED (integer_type_node)),
-                    TYPE_MODE (integer_type_node));
-#endif
 }
 
-/* The maximum number of bytes to copy using pairs of load/store instructions.
-   If a block is larger than this then a loop will be generated to copy
-   MAX_MOVE_BYTES chunks at a time.  The value of 32 is a semi-arbitary choice.
-   A customer uses Dhrystome as their benchmark, and Dhrystone has a 31 byte
-   string copy in it.  */
-#define MAX_MOVE_BYTES 32
-
 /* Expand string/block move operations.
 
    operands[0] is the pointer to the destination.
@@ -2687,8 +2186,7 @@ block_move_call (dest_reg, src_reg, bytes_rtx)
    operands[3] is the alignment.  */
 
 void
-m32r_expand_block_move (operands)
-     rtx operands[];
+m32r_expand_block_move (rtx operands[])
 {
   rtx           orig_dst  = operands[0];
   rtx           orig_src  = operands[1];
@@ -2726,15 +2224,17 @@ m32r_expand_block_move (operands)
   /* If necessary, generate a loop to handle the bulk of the copy.  */
   if (bytes)
     {
-      rtx label;
-      rtx final_src;
+      rtx label = NULL_RTX;
+      rtx final_src = NULL_RTX;
       rtx at_a_time = GEN_INT (MAX_MOVE_BYTES);
       rtx rounded_total = GEN_INT (bytes);
+      rtx new_dst_reg = gen_reg_rtx (SImode);
+      rtx new_src_reg = gen_reg_rtx (SImode);
 
       /* If we are going to have to perform this loop more than
         once, then generate a label and compute the address the
         source register will contain upon completion of the final
-        itteration.  */
+        iteration.  */
       if (bytes > MAX_MOVE_BYTES)
        {
          final_src = gen_reg_rtx (Pmode);
@@ -2755,7 +2255,10 @@ m32r_expand_block_move (operands)
         to the word after the end of the source block, and dst_reg to point
         to the last word of the destination block, provided that the block
         is MAX_MOVE_BYTES long.  */
-      emit_insn (gen_movstrsi_internal (dst_reg, src_reg, at_a_time));
+      emit_insn (gen_movmemsi_internal (dst_reg, src_reg, at_a_time,
+                                       new_dst_reg, new_src_reg));
+      emit_move_insn (dst_reg, new_dst_reg);
+      emit_move_insn (src_reg, new_src_reg);
       emit_insn (gen_addsi3 (dst_reg, dst_reg, GEN_INT (4)));
       
       if (bytes > MAX_MOVE_BYTES)
@@ -2766,7 +2269,9 @@ m32r_expand_block_move (operands)
     }
 
   if (leftover)
-    emit_insn (gen_movstrsi_internal (dst_reg, src_reg, GEN_INT (leftover)));
+    emit_insn (gen_movmemsi_internal (dst_reg, src_reg, GEN_INT (leftover),
+                                     gen_reg_rtx (SImode),
+                                     gen_reg_rtx (SImode)));
 }
 
 \f
@@ -2778,10 +2283,8 @@ m32r_expand_block_move (operands)
    operands[3] is a temp register.
    operands[4] is a temp register.  */
 
-char *
-m32r_output_block_move (insn, operands)
-     rtx insn ATTRIBUTE_UNUSED;
-     rtx operands[];
+void
+m32r_output_block_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
 {
   HOST_WIDE_INT bytes = INTVAL (operands[2]);
   int          first_time;
@@ -2794,7 +2297,7 @@ m32r_output_block_move (insn, operands)
      stores are done without any increment, then the remaining ones can use
      the pre-increment addressing mode.
      
-     Note: expand_block_move() also relies upon this behaviour when building
+     Note: expand_block_move() also relies upon this behavior when building
      loops to copy large blocks.  */
   first_time = 1;
   
@@ -2804,17 +2307,17 @@ m32r_output_block_move (insn, operands)
        {
          if (first_time)
            {
-             output_asm_insn ("ld\t%3, %p1", operands);
-             output_asm_insn ("ld\t%4, %p1", operands);
-             output_asm_insn ("st\t%3, @%0", operands);
-             output_asm_insn ("st\t%4, %s0", operands);
+             output_asm_insn ("ld\t%5, %p1", operands);
+             output_asm_insn ("ld\t%6, %p1", operands);
+             output_asm_insn ("st\t%5, @%0", operands);
+             output_asm_insn ("st\t%6, %s0", operands);
            }
          else
            {
-             output_asm_insn ("ld\t%3, %p1", operands);
-             output_asm_insn ("ld\t%4, %p1", operands);
-             output_asm_insn ("st\t%3, %s0", operands);
-             output_asm_insn ("st\t%4, %s0", operands);
+             output_asm_insn ("ld\t%5, %p1", operands);
+             output_asm_insn ("ld\t%6, %p1", operands);
+             output_asm_insn ("st\t%5, %s0", operands);
+             output_asm_insn ("st\t%6, %s0", operands);
            }
 
          bytes -= 8;
@@ -2824,15 +2327,15 @@ m32r_output_block_move (insn, operands)
          if (bytes > 4)
            got_extra = 1;
          
-         output_asm_insn ("ld\t%3, %p1", operands);
+         output_asm_insn ("ld\t%5, %p1", operands);
          
          if (got_extra)
-           output_asm_insn ("ld\t%4, %p1", operands);
+           output_asm_insn ("ld\t%6, %p1", operands);
                
          if (first_time)
-           output_asm_insn ("st\t%3, @%0", operands);
+           output_asm_insn ("st\t%5, @%0", operands);
          else
-           output_asm_insn ("st\t%3, %s0", operands);
+           output_asm_insn ("st\t%5, %s0", operands);
 
          bytes -= 4;
        }
@@ -2844,20 +2347,25 @@ m32r_output_block_move (insn, operands)
             valid memory [since we don't get called if things aren't properly
             aligned].  */
          int dst_offset = first_time ? 0 : 4;
+         /* The amount of increment we have to make to the
+            destination pointer.  */
+         int dst_inc_amount = dst_offset + bytes - 4;
+         /* The same for the source pointer.  */
+         int src_inc_amount = bytes;
          int last_shift;
          rtx my_operands[3];
 
          /* If got_extra is true then we have already loaded
             the next word as part of loading and storing the previous word.  */
          if (! got_extra)
-           output_asm_insn ("ld\t%4, @%1", operands);
+           output_asm_insn ("ld\t%6, @%1", operands);
 
          if (bytes >= 2)
            {
              bytes -= 2;
 
-             output_asm_insn ("sra3\t%3, %4, #16", operands);
-             my_operands[0] = operands[3];
+             output_asm_insn ("sra3\t%5, %6, #16", operands);
+             my_operands[0] = operands[5];
              my_operands[1] = GEN_INT (dst_offset);
              my_operands[2] = operands[0];
              output_asm_insn ("sth\t%0, @(%1,%2)", my_operands);
@@ -2878,35 +2386,68 @@ m32r_output_block_move (insn, operands)
 
          if (bytes > 0)
            {
-             my_operands[0] = operands[4];
+             my_operands[0] = operands[6];
              my_operands[1] = GEN_INT (last_shift);
              output_asm_insn ("srai\t%0, #%1", my_operands);
-             my_operands[0] = operands[4];
+             my_operands[0] = operands[6];
              my_operands[1] = GEN_INT (dst_offset);
              my_operands[2] = operands[0];
              output_asm_insn ("stb\t%0, @(%1,%2)", my_operands);
            }
+
+         /* Update the destination pointer if needed.  We have to do
+            this so that the patterns matches what we output in this
+            function.  */
+         if (dst_inc_amount
+             && !find_reg_note (insn, REG_UNUSED, operands[0]))
+           {
+             my_operands[0] = operands[0];
+             my_operands[1] = GEN_INT (dst_inc_amount);
+             output_asm_insn ("addi\t%0, #%1", my_operands);
+           }
+         
+         /* Update the source pointer if needed.  We have to do this
+            so that the patterns matches what we output in this
+            function.  */
+         if (src_inc_amount
+             && !find_reg_note (insn, REG_UNUSED, operands[1]))
+           {
+             my_operands[0] = operands[1];
+             my_operands[1] = GEN_INT (src_inc_amount);
+             output_asm_insn ("addi\t%0, #%1", my_operands);
+           }
          
          bytes = 0;
        }
 
       first_time = 0;
     }
-
-  return "";
 }
 
-/* Return true if op is an integer constant, less than or equal to
-   MAX_MOVE_BYTES.  */
+/* Return true if using NEW_REG in place of OLD_REG is ok.  */
+
 int
-m32r_block_immediate_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+m32r_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
+                          unsigned int new_reg)
 {
-  if (GET_CODE (op) != CONST_INT
-      || INTVAL (op) > MAX_MOVE_BYTES
-      || INTVAL (op) <= 0)
+  /* Interrupt routines can't clobber any register that isn't already used.  */
+  if (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl))
+      && !regs_ever_live[new_reg])
+    return 0;
+
+  /* We currently emit epilogues as text, not rtl, so the liveness
+     of the return address register isn't visible.  */
+  if (current_function_is_leaf && new_reg == RETURN_ADDR_REGNUM)
     return 0;
 
   return 1;
 }
+
+rtx
+m32r_return_addr (int count)
+{
+  if (count != 0)
+    return const0_rtx;
+  
+  return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNUM);
+}