OSDN Git Service

* config/mmix/mmix.h (FUNCTION_INCOMING_ARG_REGNO_P): Don't define
[pf3gnuchains/gcc-fork.git] / gcc / config / mmix / mmix.c
index 7dbfb2e..a55b0dc 100644 (file)
@@ -1,12 +1,13 @@
 /* Definitions of target machine for GNU compiler, for MMIX.
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Hans-Peter Nilsson (hp@bitrange.com)
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,12 +16,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -52,9 +54,19 @@ Boston, MA 02111-1307, USA.  */
 
 /* We have no means to tell DWARF 2 about the register stack, so we need
    to store the return address on the stack if an exception can get into
-   this function.  FIXME: Narrow condition.  */
-#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS \
- (flag_exceptions && ! leaf_function_p ())
+   this function.  FIXME: Narrow condition.  Before any whole-function
+   analysis, df_regs_ever_live_p () isn't initialized.  We know it's up-to-date
+   after reload_completed; it may contain incorrect information some time
+   before that.  Within a RTL sequence (after a call to start_sequence,
+   such as in RTL expanders), leaf_function_p doesn't see all insns
+   (perhaps any insn).  But regs_ever_live is up-to-date when
+   leaf_function_p () isn't, so we "or" them together to get accurate
+   information.  FIXME: Some tweak to leaf_function_p might be
+   preferable.  */
+#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS                        \
+ (flag_exceptions                                              \
+  && ((reload_completed && df_regs_ever_live_p (MMIX_rJ_REGNUM))       \
+      || !leaf_function_p ()))
 
 #define IS_MMIX_EH_RETURN_DATA_REG(REGNO)      \
  (current_function_calls_eh_return             \
@@ -68,11 +80,15 @@ Boston, MA 02111-1307, USA.  */
    registers.  In effect this makes unused call-saved registers to be used
    as call-clobbered registers.  The benefit comes from keeping the number
    of local registers (value of rL) low, since there's a cost of
-   increasing rL and clearing unused (unset) registers with lower numbers.  */
+   increasing rL and clearing unused (unset) registers with lower numbers.
+   Don't translate while outputting the prologue.  */
 #define MMIX_OUTPUT_REGNO(N)                                   \
  (TARGET_ABI_GNU                                               \
   || (int) (N) < MMIX_RETURN_VALUE_REGNUM                      \
   || (int) (N) > MMIX_LAST_STACK_REGISTER_REGNUM               \
+  || cfun == NULL                                              \
+  || cfun->machine == NULL                                     \
+  || cfun->machine->in_prologue                                        \
   ? (N) : ((N) - MMIX_RETURN_VALUE_REGNUM                      \
           + cfun->machine->highest_saved_stack_register + 1))
 
@@ -90,32 +106,36 @@ Boston, MA 02111-1307, USA.  */
 rtx mmix_compare_op0;
 rtx mmix_compare_op1;
 
-/* We ignore some options with arguments.  They are passed to the linker,
-   but also ends up here because they start with "-m".  We tell the driver
-   to store them in a variable we don't inspect.  */
-const char *mmix_cc1_ignored_option;
-
 /* Declarations of locals.  */
 
 /* Intermediate for insn output.  */
 static int mmix_output_destination_register;
 
 static void mmix_output_shiftvalue_op_from_str
-  PARAMS ((FILE *, const char *, HOST_WIDEST_INT));
-static void mmix_output_shifted_value PARAMS ((FILE *, HOST_WIDEST_INT));
-static void mmix_output_condition PARAMS ((FILE *, rtx, int));
-static HOST_WIDEST_INT mmix_intval PARAMS ((rtx));
-static void mmix_output_octa PARAMS ((FILE *, HOST_WIDEST_INT, int));
-static bool mmix_assemble_integer PARAMS ((rtx, unsigned int, int));
-static struct machine_function * mmix_init_machine_status PARAMS ((void));
-static void mmix_encode_section_info PARAMS ((tree, int));
-static const char *mmix_strip_name_encoding PARAMS ((const char *));
-
-extern void mmix_target_asm_function_prologue
-  PARAMS ((FILE *, HOST_WIDE_INT));
-extern void mmix_target_asm_function_epilogue
-  PARAMS ((FILE *, HOST_WIDE_INT));
-
+  (FILE *, const char *, HOST_WIDEST_INT);
+static void mmix_output_shifted_value (FILE *, HOST_WIDEST_INT);
+static void mmix_output_condition (FILE *, rtx, int);
+static HOST_WIDEST_INT mmix_intval (rtx);
+static void mmix_output_octa (FILE *, HOST_WIDEST_INT, int);
+static bool mmix_assemble_integer (rtx, unsigned int, int);
+static struct machine_function *mmix_init_machine_status (void);
+static void mmix_encode_section_info (tree, rtx, int);
+static const char *mmix_strip_name_encoding (const char *);
+static void mmix_emit_sp_add (HOST_WIDE_INT offset);
+static void mmix_target_asm_function_prologue (FILE *, HOST_WIDE_INT);
+static void mmix_target_asm_function_end_prologue (FILE *);
+static void mmix_target_asm_function_epilogue (FILE *, HOST_WIDE_INT);
+static void mmix_reorg (void);
+static void mmix_asm_output_mi_thunk
+  (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
+static void mmix_setup_incoming_varargs
+  (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);
+static void mmix_file_start (void);
+static void mmix_file_end (void);
+static bool mmix_rtx_costs (rtx, int, int, int *);
+static rtx mmix_struct_value_rtx (tree, int);
+static bool mmix_pass_by_reference (CUMULATIVE_ARGS *,
+                                   enum machine_mode, const_tree, bool);
 
 /* Target structure macros.  Listed by node.  See `Using and Porting GCC'
    for a general description.  */
@@ -136,6 +156,9 @@ extern void mmix_target_asm_function_epilogue
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue
 
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE mmix_target_asm_function_end_prologue
+
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue
 
@@ -144,6 +167,45 @@ extern void mmix_target_asm_function_epilogue
 #undef TARGET_STRIP_NAME_ENCODING
 #define TARGET_STRIP_NAME_ENCODING  mmix_strip_name_encoding
 
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK mmix_asm_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START mmix_file_start
+#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
+#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END mmix_file_end
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS mmix_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_0
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG mmix_reorg
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
+#if 0
+/* Apparently not doing TRT if int < register-size.  FIXME: Perhaps
+   FUNCTION_VALUE and LIBCALL_VALUE needs tweaking as some ports say.  */
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#endif
+
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX mmix_struct_value_rtx
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS mmix_setup_incoming_varargs
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE mmix_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Functions that are expansions for target macros.
@@ -152,7 +214,7 @@ struct gcc_target targetm = TARGET_INITIALIZER;
 /* OVERRIDE_OPTIONS.  */
 
 void
-mmix_override_options ()
+mmix_override_options (void)
 {
   /* Should we err or should we warn?  Hmm.  At least we must neutralize
      it.  For example the wrong kind of case-tables will be generated with
@@ -161,7 +223,7 @@ mmix_override_options ()
      labels.  */
   if (flag_pic)
     {
-      warning ("-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");
+      warning (0, "-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");
       flag_pic = 0;
     }
 }
@@ -169,7 +231,7 @@ mmix_override_options ()
 /* INIT_EXPANDERS.  */
 
 void
-mmix_init_expanders ()
+mmix_init_expanders (void)
 {
   init_machine_status = mmix_init_machine_status;
 }
@@ -177,7 +239,7 @@ mmix_init_expanders ()
 /* Set the per-function data.  */
 
 static struct machine_function *
-mmix_init_machine_status ()
+mmix_init_machine_status (void)
 {
   return ggc_alloc_cleared (sizeof (struct machine_function));
 }
@@ -185,12 +247,10 @@ mmix_init_machine_status ()
 /* DATA_ALIGNMENT.
    We have trouble getting the address of stuff that is located at other
    than 32-bit alignments (GETA requirements), so try to give everything
-   at least 32-bit alignment. */
+   at least 32-bit alignment.  */
 
 int
-mmix_data_alignment (type, basic_align)
-     tree type ATTRIBUTE_UNUSED;
-     int basic_align;
+mmix_data_alignment (tree type ATTRIBUTE_UNUSED, int basic_align)
 {
   if (basic_align < 32)
     return 32;
@@ -201,9 +261,7 @@ mmix_data_alignment (type, basic_align)
 /* CONSTANT_ALIGNMENT.  */
 
 int
-mmix_constant_alignment (constant, basic_align)
-     tree constant ATTRIBUTE_UNUSED;
-     int basic_align;
+mmix_constant_alignment (tree constant ATTRIBUTE_UNUSED, int basic_align)
 {
   if (basic_align < 32)
     return 32;
@@ -214,9 +272,7 @@ mmix_constant_alignment (constant, basic_align)
 /* LOCAL_ALIGNMENT.  */
 
 int
-mmix_local_alignment (type, basic_align)
-     tree type ATTRIBUTE_UNUSED;
-     int basic_align;
+mmix_local_alignment (tree type ATTRIBUTE_UNUSED, int basic_align)
 {
   if (basic_align < 32)
     return 32;
@@ -227,7 +283,7 @@ mmix_local_alignment (type, basic_align)
 /* CONDITIONAL_REGISTER_USAGE.  */
 
 void
-mmix_conditional_register_usage ()
+mmix_conditional_register_usage (void)
 {
   int i;
 
@@ -241,11 +297,11 @@ mmix_conditional_register_usage ()
 
       /* Change the default from the mmixware ABI.  For the GNU ABI,
         $15..$30 are call-saved just as $0..$14.  There must be one
-        call-clobbered local register for the "hole" describing number of
-        saved local registers saved by PUSHJ/PUSHGO during the function
-        call, receiving the return value at return.  So best is to use
-        the highest, $31.  It's already marked call-clobbered for the
-        mmixware ABI.  */
+        call-clobbered local register for the "hole" that holds the
+        number of saved local registers saved by PUSHJ/PUSHGO during the
+        function call, receiving the return value at return.  So best is
+        to use the highest, $31.  It's already marked call-clobbered for
+        the mmixware ABI.  */
       for (i = 15; i <= 30; i++)
        call_used_regs[i] = 0;
 
@@ -263,13 +319,41 @@ mmix_conditional_register_usage ()
        reg_names[i]++;
 }
 
+/* INCOMING_REGNO and OUTGOING_REGNO worker function.
+   Those two macros must only be applied to function argument
+   registers.  FIXME: for their current use in gcc, it'd be better
+   with an explicit specific additional FUNCTION_INCOMING_ARG_REGNO_P
+   a'la FUNCTION_ARG / FUNCTION_INCOMING_ARG instead of forcing the
+   target to commit to a fixed mapping and for any unspecified
+   register use.  */
+
+int
+mmix_opposite_regno (int regno, int incoming)
+{
+  if (!mmix_function_arg_regno_p (regno, incoming))
+    return regno;
+
+  return
+    regno - (incoming
+            ? MMIX_FIRST_INCOMING_ARG_REGNUM - MMIX_FIRST_ARG_REGNUM
+            : MMIX_FIRST_ARG_REGNUM - MMIX_FIRST_INCOMING_ARG_REGNUM);
+}
+
+/* LOCAL_REGNO.
+   All registers that are part of the register stack and that will be
+   saved are local.  */
+
+int
+mmix_local_regno (int regno)
+{
+  return regno <= MMIX_LAST_STACK_REGISTER_REGNUM && !call_used_regs[regno];
+}
+
 /* PREFERRED_RELOAD_CLASS.
    We need to extend the reload class of REMAINDER_REG and HIMULT_REG.  */
 
 enum reg_class
-mmix_preferred_reload_class (x, class)
-     rtx x ATTRIBUTE_UNUSED;
-     enum reg_class class;
+mmix_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
 {
   /* FIXME: Revisit.  */
   return GET_CODE (x) == MOD && GET_MODE (x) == DImode
@@ -280,9 +364,8 @@ mmix_preferred_reload_class (x, class)
    We need to extend the reload class of REMAINDER_REG and HIMULT_REG.  */
 
 enum reg_class
-mmix_preferred_output_reload_class (x, class)
-     rtx x ATTRIBUTE_UNUSED;
-     enum reg_class class;
+mmix_preferred_output_reload_class (rtx x ATTRIBUTE_UNUSED,
+                                   enum reg_class class)
 {
   /* FIXME: Revisit.  */
   return GET_CODE (x) == MOD && GET_MODE (x) == DImode
@@ -293,11 +376,10 @@ mmix_preferred_output_reload_class (x, class)
    We need to reload regs of REMAINDER_REG and HIMULT_REG elsewhere.  */
 
 enum reg_class
-mmix_secondary_reload_class (class, mode, x, in_p)
-     enum reg_class class;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx x ATTRIBUTE_UNUSED;
-     int in_p ATTRIBUTE_UNUSED;
+mmix_secondary_reload_class (enum reg_class class,
+                            enum machine_mode mode ATTRIBUTE_UNUSED,
+                            rtx x ATTRIBUTE_UNUSED,
+                            int in_p ATTRIBUTE_UNUSED)
 {
   if (class == REMAINDER_REG
       || class == HIMULT_REG
@@ -310,9 +392,7 @@ mmix_secondary_reload_class (class, mode, x, in_p)
 /* CONST_OK_FOR_LETTER_P.  */
 
 int
-mmix_const_ok_for_letter_p (value, c)
-     HOST_WIDE_INT value;
-     int c;
+mmix_const_ok_for_letter_p (HOST_WIDE_INT value, int c)
 {
   return
     (c == 'I' ? value >= 0 && value <= 255
@@ -329,9 +409,7 @@ mmix_const_ok_for_letter_p (value, c)
 /* CONST_DOUBLE_OK_FOR_LETTER_P.  */
 
 int
-mmix_const_double_ok_for_letter_p (value, c)
-     rtx value;
-     int c;
+mmix_const_double_ok_for_letter_p (rtx value, int c)
 {
   return
     (c == 'G' ? value == CONST0_RTX (GET_MODE (value))
@@ -343,10 +421,7 @@ mmix_const_double_ok_for_letter_p (value, c)
    CONST_INT:s, but rather often as CONST_DOUBLE:s.  */
 
 int
-mmix_extra_constraint (x, c, strict)
-     rtx x;
-     int c;
-     int strict;
+mmix_extra_constraint (rtx x, int c, int strict)
 {
   HOST_WIDEST_INT value;
 
@@ -398,8 +473,7 @@ mmix_extra_constraint (x, c, strict)
 /* DYNAMIC_CHAIN_ADDRESS.  */
 
 rtx
-mmix_dynamic_chain_address (frame)
-     rtx frame;
+mmix_dynamic_chain_address (rtx frame)
 {
   /* FIXME: the frame-pointer is stored at offset -8 from the current
      frame-pointer.  Unfortunately, the caller assumes that a
@@ -411,7 +485,7 @@ mmix_dynamic_chain_address (frame)
 /* STARTING_FRAME_OFFSET.  */
 
 int
-mmix_starting_frame_offset ()
+mmix_starting_frame_offset (void)
 {
   /* The old frame pointer is in the slot below the new one, so
      FIRST_PARM_OFFSET does not need to depend on whether the
@@ -428,9 +502,7 @@ mmix_starting_frame_offset ()
 /* RETURN_ADDR_RTX.  */
 
 rtx
-mmix_return_addr_rtx (count, frame)
-     int count;
-     rtx frame ATTRIBUTE_UNUSED;
+mmix_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED)
 {
   return count == 0
     ? (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS
@@ -446,7 +518,7 @@ mmix_return_addr_rtx (count, frame)
 /* SETUP_FRAME_ADDRESSES.  */
 
 void
-mmix_setup_frame_addresses ()
+mmix_setup_frame_addresses (void)
 {
   /* Nothing needed at the moment.  */
 }
@@ -455,9 +527,7 @@ mmix_setup_frame_addresses ()
    pointer.  Used to eliminate the frame pointer.  */
 
 int
-mmix_initial_elimination_offset (fromreg, toreg)
-     int fromreg;
-     int toreg;
+mmix_initial_elimination_offset (int fromreg, int toreg)
 {
   int regno;
   int fp_sp_offset
@@ -496,7 +566,7 @@ mmix_initial_elimination_offset (fromreg, toreg)
   for (regno = MMIX_FIRST_GLOBAL_REGNUM;
        regno <= 255;
        regno++)
-    if ((regs_ever_live[regno] && ! call_used_regs[regno])
+    if ((df_regs_ever_live_p (regno) && ! call_used_regs[regno])
        || IS_MMIX_EH_RETURN_DATA_REG (regno))
       fp_sp_offset += 8;
 
@@ -510,21 +580,12 @@ mmix_initial_elimination_offset (fromreg, toreg)
    one that must go on stack.  */
 
 rtx
-mmix_function_arg (argsp, mode, type, named, incoming)
-     const CUMULATIVE_ARGS * argsp;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
-     int incoming;
-{
-  /* Handling of the positional dummy parameter for varargs gets nasty.
-     Check execute/991216-3 and function.c:assign_params.  We have to say
-     that the dummy parameter goes on stack in order to get the correct
-     offset when va_start and va_arg is applied.  FIXME: Should do TRT by
-     itself in the gcc core.  */
-  if ((! named && incoming && current_function_varargs) || argsp->now_varargs)
-    return NULL_RTX;
-
+mmix_function_arg (const CUMULATIVE_ARGS *argsp,
+                  enum machine_mode mode,
+                  tree type,
+                  int named ATTRIBUTE_UNUSED,
+                  int incoming)
+{
   /* Last-argument marker.  */
   if (type == void_type_node)
     return (argsp->regs < MMIX_MAX_ARGS_IN_REGS)
@@ -535,7 +596,7 @@ mmix_function_arg (argsp, mode, type, named, incoming)
       : NULL_RTX;
 
   return (argsp->regs < MMIX_MAX_ARGS_IN_REGS
-         && !MUST_PASS_IN_STACK (mode, type)
+         && !targetm.calls.must_pass_in_stack (mode, type)
          && (GET_MODE_BITSIZE (mode) <= 64
              || argsp->lib
              || TARGET_LIBFUNC))
@@ -550,29 +611,28 @@ mmix_function_arg (argsp, mode, type, named, incoming)
 /* Returns nonzero for everything that goes by reference, 0 for
    everything that goes by value.  */
 
-int
-mmix_function_arg_pass_by_reference (argsp, mode, type, named)
-     const CUMULATIVE_ARGS * argsp;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+static bool
+mmix_pass_by_reference (CUMULATIVE_ARGS *argsp, enum machine_mode mode,
+                       const_tree type, bool named ATTRIBUTE_UNUSED)
 {
-  /* FIXME: Check: I'm not sure the MUST_PASS_IN_STACK check is
+  /* FIXME: Check: I'm not sure the must_pass_in_stack check is
      necessary.  */
-  return
-    MUST_PASS_IN_STACK (mode, type)
-    || (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8
-       && !TARGET_LIBFUNC
-       && !argsp->lib);
+  if (targetm.calls.must_pass_in_stack (mode, type))
+    return true;
+
+  if (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8
+      && !TARGET_LIBFUNC
+      && (!argsp || !argsp->lib))
+    return true;
+
+  return false;
 }
 
 /* Return nonzero if regno is a register number where a parameter is
    passed, and 0 otherwise.  */
 
 int
-mmix_function_arg_regno_p (regno, incoming)
-     int regno;
-     int incoming;
+mmix_function_arg_regno_p (int regno, int incoming)
 {
   int first_arg_regnum
     = incoming ? MMIX_FIRST_INCOMING_ARG_REGNUM : MMIX_FIRST_ARG_REGNUM;
@@ -584,9 +644,7 @@ mmix_function_arg_regno_p (regno, incoming)
 /* FUNCTION_OUTGOING_VALUE.  */
 
 rtx
-mmix_function_outgoing_value (valtype, func)
-     tree valtype;
-     tree func ATTRIBUTE_UNUSED;
+mmix_function_outgoing_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode = TYPE_MODE (valtype);
   enum machine_mode cmode;
@@ -603,8 +661,22 @@ mmix_function_outgoing_value (valtype, func)
     return
       gen_rtx_REG (mode, MMIX_OUTGOING_RETURN_VALUE_REGNUM);
 
-  /* A complex type, made up of components.  */
-  cmode = TYPE_MODE (TREE_TYPE (valtype));
+  if (COMPLEX_MODE_P (mode))
+    /* A complex type, made up of components.  */
+    cmode = TYPE_MODE (TREE_TYPE (valtype));
+  else
+    {
+      /* Of the other larger-than-register modes, we only support
+        scalar mode TImode.  (At least, that's the only one that's
+        been rudimentally tested.)  Make sure we're alerted for
+        unexpected cases.  */
+      if (mode != TImode)
+       sorry ("support for mode %qs", GET_MODE_NAME (mode));
+
+      /* In any case, we will fill registers to the natural size.  */
+      cmode = DImode;
+    }
+
   nregs = ((GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD);
 
   /* We need to take care of the effect of the register hole on return
@@ -627,16 +699,23 @@ mmix_function_outgoing_value (valtype, func)
   vec[nregs - 1]
     = gen_rtx_EXPR_LIST (VOIDmode,
                         gen_rtx_REG (cmode, first_val_regnum + nregs - 1),
-                        GEN_INT (0));
+                        const0_rtx);
 
   return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs, vec));
 }
 
+/* FUNCTION_VALUE_REGNO_P.  */
+
+int
+mmix_function_value_regno_p (int regno)
+{
+  return regno == MMIX_RETURN_VALUE_REGNUM;
+}
+
 /* EH_RETURN_DATA_REGNO. */
 
 int
-mmix_eh_return_data_regno (n)
-     int n ATTRIBUTE_UNUSED;
+mmix_eh_return_data_regno (int n)
 {
   if (n >= 0 && n < 4)
     return MMIX_EH_RETURN_DATA_REGNO_START + n;
@@ -647,7 +726,7 @@ mmix_eh_return_data_regno (n)
 /* EH_RETURN_STACKADJ_RTX. */
 
 rtx
-mmix_eh_return_stackadj_rtx ()
+mmix_eh_return_stackadj_rtx (void)
 {
   return gen_rtx_REG (Pmode, MMIX_EH_RETURN_STACKADJ_REGNUM);
 }
@@ -655,362 +734,46 @@ mmix_eh_return_stackadj_rtx ()
 /* EH_RETURN_HANDLER_RTX.  */
 
 rtx
-mmix_eh_return_handler_rtx ()
+mmix_eh_return_handler_rtx (void)
 {
-  return
-    gen_rtx_REG (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
+  return gen_rtx_REG (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
 }
 
 /* ASM_PREFERRED_EH_DATA_FORMAT. */
 
 int
-mmix_asm_preferred_eh_data_format (code, global)
-     int code ATTRIBUTE_UNUSED;
-     int global ATTRIBUTE_UNUSED;
+mmix_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED,
+                                  int global ATTRIBUTE_UNUSED)
 {
   /* This is the default (was at 2001-07-20).  Revisit when needed.  */
   return DW_EH_PE_absptr;
 }
 
-/* Emit the function prologue.  For simplicity while the port is still
-   in a flux, we do it as text rather than the now preferred RTL way,
-   as (define_insn "function_prologue").
+/* Make a note that we've seen the beginning of the prologue.  This
+   matters to whether we'll translate register numbers as calculated by
+   mmix_reorg.  */
 
-   FIXME: Translate to RTL and/or optimize some of the DWARF 2 stuff.  */
-
-void
-mmix_target_asm_function_prologue (stream, locals_size)
-     FILE *stream;
-     HOST_WIDE_INT locals_size;
+static void
+mmix_target_asm_function_prologue (FILE *stream ATTRIBUTE_UNUSED,
+                                  HOST_WIDE_INT framesize ATTRIBUTE_UNUSED)
 {
-  int regno;
-  int stack_space_to_allocate
-    = (current_function_outgoing_args_size
-       + current_function_pretend_args_size
-       + (int) locals_size + 7) & ~7;
-  int offset = -8;
-  int doing_dwarf = dwarf2out_do_frame ();
-  long cfa_offset = 0;
-
-  /* Guard our assumptions.  Very low priority FIXME.  */
-  if (locals_size != (int) locals_size)
-    error ("stack frame too big");
-
-  /* Add room needed to save global non-register-stack registers.  */
-  for (regno = 255;
-       regno >= MMIX_FIRST_GLOBAL_REGNUM;
-       regno--)
-    /* Note that we assume that the frame-pointer-register is one of these
-       registers, in which case we don't count it here.  */
-    if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-         && regs_ever_live[regno] && !call_used_regs[regno]))
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      stack_space_to_allocate += 8;
-
-  /* If we do have a frame-pointer, add room for it.  */
-  if (frame_pointer_needed)
-    stack_space_to_allocate += 8;
-
-  /* If we have a non-local label, we need to be able to unwind to it, so
-     store the current register stack pointer.  Also store the return
-     address if we do that.  */
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    stack_space_to_allocate += 16;
-  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    /* If we do have a saved return-address slot, add room for it.  */
-    stack_space_to_allocate += 8;
-
-  /* Make sure we don't get an unaligned stack.  */
-  if ((stack_space_to_allocate % 8) != 0)
-    internal_error ("stack frame not a multiple of 8 bytes: %d",
-                   stack_space_to_allocate);
-
-  if (current_function_pretend_args_size)
-    {
-      int mmix_first_vararg_reg
-       = (MMIX_FIRST_INCOMING_ARG_REGNUM
-          + (MMIX_MAX_ARGS_IN_REGS
-             - current_function_pretend_args_size / 8));
-
-      for (regno
-            = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
-          regno >= mmix_first_vararg_reg;
-          regno--)
-       {
-         if (offset < 0)
-           {
-             int stack_chunk
-               = stack_space_to_allocate > (256 - 8)
-               ? (256 - 8) : stack_space_to_allocate;
-
-             fprintf (stream, "\tSUBU %s,%s,%d\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      stack_chunk);
-
-             if (doing_dwarf)
-               {
-                 /* Each call to dwarf2out_def_cfa overrides the previous
-                    setting; they don't accumulate.  We must keep track
-                    of the offset ourselves.  */
-                 cfa_offset += stack_chunk;
-                 if (!frame_pointer_needed)
-                   dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                      cfa_offset);
-               }
-             offset += stack_chunk;
-             stack_space_to_allocate -= stack_chunk;
-           }
-
-         fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  offset);
-
-         /* These registers aren't actually saved (as in "will be
-            restored"), so don't tell DWARF2 they're saved.  */
-
-         offset -= 8;
-       }
-    }
-
-  /* Store the frame-pointer.  */
-
-  if (frame_pointer_needed)
-    {
-      if (offset < 0)
-       {
-         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
-         int stack_chunk
-           = stack_space_to_allocate > (256 - 8 - 8)
-           ? (256 - 8 - 8) : stack_space_to_allocate;
-
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_chunk);
-         if (doing_dwarf)
-           cfa_offset += stack_chunk;
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-       }
-
-      fprintf (stream, "\tSTOU %s,%s,%d\n\tADDU %s,%s,%d\n",
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset,
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset + 8);
-      if (doing_dwarf)
-       {
-         /* If we're using the frame-pointer, then we just need this CFA
-            definition basing on that value (often equal to the CFA).
-            Further changes to the stack-pointer do not affect the
-            frame-pointer, so we conditionalize them below on
-            !frame_pointer_needed.  */
-         dwarf2out_def_cfa ("", MMIX_FRAME_POINTER_REGNUM,
-                            -cfa_offset + offset + 8);
-
-         dwarf2out_reg_save ("", MMIX_FRAME_POINTER_REGNUM,
-                             -cfa_offset + offset);
-       }
-
-      offset -= 8;
-    }
-
-  if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    {
-      /* Store the return-address, if one is needed on the stack.  We
-        usually store it in a register when needed, but that doesn't work
-        with -fexceptions.  */
-
-      if (offset < 0)
-       {
-         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
-         int stack_chunk
-           = stack_space_to_allocate > (256 - 8 - 8)
-           ? (256 - 8 - 8) : stack_space_to_allocate;
-
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_chunk);
-         if (doing_dwarf)
-           {
-             cfa_offset += stack_chunk;
-             if (!frame_pointer_needed)
-               dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                  cfa_offset);
-           }
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-       }
-
-      fprintf (stream, "\tGET $255,rJ\n\tSTOU $255,%s,%d\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset);
-      if (doing_dwarf)
-       dwarf2out_return_save ("", -cfa_offset + offset);
-      offset -= 8;
-    }
-  else if (MMIX_CFUN_HAS_LANDING_PAD)
-    offset -= 8;
-
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    {
-      /* Store the register defining the numbering of local registers, so
-        we know how long to unwind the register stack.  */
-
-      if (offset < 0)
-       {
-         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
-         int stack_chunk
-           = stack_space_to_allocate > (256 - 8 - 8)
-           ? (256 - 8 - 8) : stack_space_to_allocate;
-
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_chunk);
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-
-         if (doing_dwarf)
-           {
-             cfa_offset += stack_chunk;
-             if (!frame_pointer_needed)
-               dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                cfa_offset);
-           }
-       }
-
-      /* We don't tell dwarf2 about this one; we just have it to unwind
-        the register stack at landing pads.  FIXME: It's a kludge because
-        we can't describe the effect of the PUSHJ and PUSHGO insns on the
-        register stack at the moment.  Best thing would be to handle it
-        like stack-pointer offsets.  Better: some hook into dwarf2out.c
-        to produce DW_CFA_expression:s that specify the increment of rO,
-        and unwind it at eh_return (preferred) or at the landing pad.
-        Then saves to $0..$G-1 could be specified through that register.  */
-
-      fprintf (stream, "\tGET $255,rO\n\tSTOU $255,%s,%d\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-
-      offset -= 8;
-    }
-
-  /* After the return-address and the frame-pointer, we have the local
-     variables.  They're the ones that may have an "unaligned" size.  */
-  offset -= (locals_size + 7) & ~7;
-
-  /* Now store all registers that are global, i.e. not saved by the
-     register file machinery.
-
-     It is assumed that the frame-pointer is one of these registers, so it
-     is explicitly excluded in the count.  */
-
-  for (regno = 255;
-       regno >= MMIX_FIRST_GLOBAL_REGNUM;
-       regno--)
-    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-        && regs_ever_live[regno] && ! call_used_regs[regno])
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      {
-       if (offset < 0)
-         {
-           int stack_chunk;
-
-           /* Since the local variables go above, we may get a large
-              offset here.  */
-           if (offset < -248)
-             {
-               /* We're not going to access the locals area in the
-                  prologue, so we'll just silently subtract the slab we
-                  will not access.  */
-               stack_chunk =
-                 stack_space_to_allocate > (256 - offset - 8)
-                 ? (256 - offset - 8) : stack_space_to_allocate;
-
-               mmix_output_register_setting (stream, 255, stack_chunk, 1);
-               fprintf (stream, "\tSUBU %s,%s,$255\n",
-                        reg_names[MMIX_STACK_POINTER_REGNUM],
-                        reg_names[MMIX_STACK_POINTER_REGNUM]);
-
-               if (doing_dwarf)
-                 {
-                   cfa_offset += stack_chunk;
-                   if (!frame_pointer_needed)
-                     dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                        cfa_offset);
-                 }
-             }
-           else
-             {
-               stack_chunk = stack_space_to_allocate > (256 - 8)
-                 ? (256 - 8) : stack_space_to_allocate;
-
-               fprintf (stream, "\tSUBU %s,%s,%d\n",
-                        reg_names[MMIX_STACK_POINTER_REGNUM],
-                        reg_names[MMIX_STACK_POINTER_REGNUM], stack_chunk);
-               if (doing_dwarf)
-                 {
-                   cfa_offset += stack_chunk;
-                   if (!frame_pointer_needed)
-                     dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                        cfa_offset);
-                 }
-             }
-
-           offset += stack_chunk;
-           stack_space_to_allocate -= stack_chunk;
-         }
-
-       fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
-              reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-       if (doing_dwarf)
-         dwarf2out_reg_save ("", regno, -cfa_offset + offset);
-       offset -= 8;
-      }
+  cfun->machine->in_prologue = 1;
+}
 
-  /* Finally, allocate room for outgoing args and local vars if room
-     wasn't allocated above.  This might be any number of bytes (well, we
-     assume it fits in a host-int).  */
-  if (stack_space_to_allocate)
-    {
-      if (stack_space_to_allocate < 256)
-       {
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_space_to_allocate);
-       }
-      else
-       {
-         mmix_output_register_setting (stream, 255,
-                                       stack_space_to_allocate, 1);
-         fprintf (stream, "\tSUBU %s,%s,$255\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM]);
-       }
+/* Make a note that we've seen the end of the prologue.  */
 
-      if (doing_dwarf)
-       {
-         cfa_offset += stack_space_to_allocate;
-         if (!frame_pointer_needed)
-           dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                              cfa_offset);
-       }
-    }
+static void
+mmix_target_asm_function_end_prologue (FILE *stream ATTRIBUTE_UNUSED)
+{
+  cfun->machine->in_prologue = 0;
 }
 
-/* MACHINE_DEPENDENT_REORG.
-   No actual rearrangements done here; just virtually by calculating the
-   highest saved stack register number used to modify the register numbers
-   at output time.  */
+/* Implement TARGET_MACHINE_DEPENDENT_REORG.  No actual rearrangements
+   done here; just virtually by calculating the highest saved stack
+   register number used to modify the register numbers at output time.  */
 
-void
-mmix_machine_dependent_reorg (first)
-     rtx first ATTRIBUTE_UNUSED;
+static void
+mmix_reorg (void)
 {
   int regno;
 
@@ -1021,7 +784,7 @@ mmix_machine_dependent_reorg (first)
   for (regno = MMIX_LAST_STACK_REGISTER_REGNUM;
        regno >= 0;
        regno--)
-    if ((regs_ever_live[regno] && !call_used_regs[regno])
+    if ((df_regs_ever_live_p (regno) && !call_used_regs[regno])
        || (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed))
       break;
 
@@ -1030,7 +793,7 @@ mmix_machine_dependent_reorg (first)
      insns to see whether they're actually used (and indeed do other less
      trivial register usage analysis and transformations), but it seems
      wasteful to optimize for unused parameter registers.  As of
-     2002-04-30, regs_ever_live[n] seems to be set for only-reads too, but
+     2002-04-30, df_regs_ever_live_p (n) seems to be set for only-reads too, but
      that might change.  */
   if (!TARGET_ABI_GNU && regno < current_function_args_info.regs - 1)
     {
@@ -1049,375 +812,74 @@ mmix_machine_dependent_reorg (first)
 
 /* TARGET_ASM_FUNCTION_EPILOGUE.  */
 
-void
-mmix_target_asm_function_epilogue (stream, locals_size)
-     FILE *stream;
-     HOST_WIDE_INT locals_size;
-
+static void
+mmix_target_asm_function_epilogue (FILE *stream,
+                                  HOST_WIDE_INT locals_size ATTRIBUTE_UNUSED)
 {
-  int regno;
-  int stack_space_to_deallocate
-    = (current_function_outgoing_args_size
-       + current_function_pretend_args_size
-       + (int) locals_size + 7) & ~7;
+  /* Emit an \n for readability of the generated assembly.  */
+  fputc ('\n', stream);
+}
 
-  /* The assumption that locals_size fits in an int is asserted in
-     mmix_target_asm_function_prologue.  */
+/* TARGET_ASM_OUTPUT_MI_THUNK.  */
 
-  /* The first address to access is beyond the outgoing_args area.  */
-  int offset = current_function_outgoing_args_size;
-
-  rtx insn = get_last_insn ();
-
-  /* If the last insn was a BARRIER, we don't have to write any code,
-     then all returns were covered by "return" insns.  */
-  if (GET_CODE (insn) == NOTE)
-    insn = prev_nonnote_insn (insn);
-  if (insn
-      && (GET_CODE (insn) == BARRIER
-         /* We must make sure that the insn really is a "return" and
-            not a conditional branch.  Try to match the return exactly,
-            and if it doesn't match, assume it is a conditional branch
-            (and output an epilogue).  */
-         || (GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == RETURN)))
+static void
+mmix_asm_output_mi_thunk (FILE *stream,
+                         tree fndecl ATTRIBUTE_UNUSED,
+                         HOST_WIDE_INT delta,
+                         HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                         tree func)
+{
+  /* If you define TARGET_STRUCT_VALUE_RTX that returns 0 (i.e. pass
+     location of structure to return as invisible first argument), you
+     need to tweak this code too.  */
+  const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
+
+  if (delta >= 0 && delta < 65536)
+    fprintf (stream, "\tINCL %s,%d\n", regname, (int)delta);
+  else if (delta < 0 && delta >= -255)
+    fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, (int)-delta);
+  else
     {
-      /* Emit an extra \n as is done with the normal epilogue.  */
-      fputc ('\n', stream);
-      return;
+      mmix_output_register_setting (stream, 255, delta, 1);
+      fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
     }
 
-  /* Add the space for global non-register-stack registers.
-     It is assumed that the frame-pointer register can be one of these
-     registers, in which case it is excluded from the count when needed.  */
-  for (regno = 255;
-       regno >= MMIX_FIRST_GLOBAL_REGNUM;
-       regno--)
-    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-        && regs_ever_live[regno] && !call_used_regs[regno])
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      stack_space_to_deallocate += 8;
-
-  /* Add in the space for register stack-pointer.  If so, always add room
-     for the saved PC.  */
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    stack_space_to_deallocate += 16;
-  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    /* If we have a saved return-address slot, add it in.  */
-    stack_space_to_deallocate += 8;
-
-  /* Add in the frame-pointer.  */
-  if (frame_pointer_needed)
-    stack_space_to_deallocate += 8;
-
-  /* Make sure we don't get an unaligned stack.  */
-  if ((stack_space_to_deallocate % 8) != 0)
-    internal_error ("stack frame not a multiple of octabyte: %d",
-                   stack_space_to_deallocate);
-
-  /* We will add back small offsets to the stack pointer as we go.
-     First, we restore all registers that are global, i.e. not saved by
-     the register file machinery.  */
-
-  for (regno = MMIX_FIRST_GLOBAL_REGNUM;
-       regno <= 255;
-       regno++)
-    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-        && regs_ever_live[regno] && !call_used_regs[regno])
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      {
-       if (offset > 255)
-         {
-           if (offset > 65535)
-             {
-               /* There's better support for incrementing than
-                  decrementing, so we might be able to optimize this as
-                  we see a need.  */
-               mmix_output_register_setting (stream, 255, offset, 1);
-               fprintf (stream, "\tADDU %s,%s,$255\n",
-                        reg_names[MMIX_STACK_POINTER_REGNUM],
-                        reg_names[MMIX_STACK_POINTER_REGNUM]);
-             }
-           else
-             fprintf (stream, "\tINCL %s,%d\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-
-           stack_space_to_deallocate -= offset;
-           offset = 0;
-         }
-
-       fprintf (stream, "\tLDOU %s,%s,%d\n",
-                reg_names[regno],
-                reg_names[MMIX_STACK_POINTER_REGNUM],
-                offset);
-       offset += 8;
-      }
-
-  /* Here is where the local variables were.  As in the prologue, they
-     might be of an unaligned size.  */
-  offset += (locals_size + 7) & ~7;
-
-
-  /* The saved register stack pointer is just below the frame-pointer
-     register.  We don't need to restore it "manually"; the POP
-     instruction does that.  */
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    offset += 16;
-  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    /* The return-address slot is just below the frame-pointer register.
-       We don't need to restore it because we don't really use it.  */
-    offset += 8;
-
-  /* Get back the old frame-pointer-value.  */
-  if (frame_pointer_needed)
-    {
-      if (offset > 255)
-       {
-         if (offset > 65535)
-           {
-             /* There's better support for incrementing than
-                decrementing, so we might be able to optimize this as
-                we see a need.  */
-             mmix_output_register_setting (stream, 255, offset, 1);
-             fprintf (stream, "\tADDU %s,%s,$255\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      reg_names[MMIX_STACK_POINTER_REGNUM]);
-           }
-         else
-           fprintf (stream, "\tINCL %s,%d\n",
-                    reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-
-         stack_space_to_deallocate -= offset;
-         offset = 0;
-       }
-
-      fprintf (stream, "\tLDOU %s,%s,%d\n",
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset);
-      offset += 8;
-    }
-
-  /* We do not need to restore pretended incoming args, just add back
-     offset to sp.  */
-  if (stack_space_to_deallocate > 65535)
-    {
-      /* There's better support for incrementing than decrementing, so
-        we might be able to optimize this as we see a need.  */
-      mmix_output_register_setting (stream, 255,
-                                   stack_space_to_deallocate, 1);
-      fprintf (stream, "\tADDU %s,%s,$255\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM]);
-    }
-  else if (stack_space_to_deallocate != 0)
-    fprintf (stream, "\tINCL %s,%d\n",
-            reg_names[MMIX_STACK_POINTER_REGNUM],
-            stack_space_to_deallocate);
-
-  if (current_function_calls_eh_return)
-    /* Adjustment the (normal) stack-pointer to that of the receiver.
-       FIXME: It would be nice if we could also adjust the register stack
-       here, but we need to express it through DWARF 2 too.  */
-    fprintf (stream, "\tADDU %s,%s,%s\n",
-            reg_names [MMIX_STACK_POINTER_REGNUM],
-            reg_names [MMIX_STACK_POINTER_REGNUM],
-            reg_names [MMIX_EH_RETURN_STACKADJ_REGNUM]);
-
-  /* The extra \n is so we have a blank line between the assembly code of
-     separate functions.  */
-  fprintf (stream, "\tPOP %d,0\n\n", MMIX_POP_ARGUMENT ());
-}
-
-/* ASM_OUTPUT_MI_THUNK.  */
-
-void
-mmix_asm_output_mi_thunk (stream, fndecl, delta, func)
-     FILE * stream;
-     tree fndecl ATTRIBUTE_UNUSED;
-     int delta;
-     tree func;
-{
-  /* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
-     (i.e. pass location of structure to return as invisible first
-     argument) you need to tweak this code too.  */
-  const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
-
-  if (delta >= 0 && delta < 65536)
-    asm_fprintf (stream, "\tINCL %s,%d\n", delta, regname);
-  else if (delta < 0 && delta >= -255)
-    asm_fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, -delta);
-  else
-    {
-      mmix_output_register_setting (stream, 255, delta, 1);
-      asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
-    }
-
-  fprintf (stream, "\tJMP ");
-  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
-  fprintf (stream, "\n");
-}
+  fprintf (stream, "\tJMP ");
+  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
+  fprintf (stream, "\n");
+}
 
 /* FUNCTION_PROFILER.  */
 
 void
-mmix_function_profiler (stream, labelno)
-     FILE *stream ATTRIBUTE_UNUSED;
-     int labelno ATTRIBUTE_UNUSED;
+mmix_function_profiler (FILE *stream ATTRIBUTE_UNUSED,
+                       int labelno ATTRIBUTE_UNUSED)
 {
   sorry ("function_profiler support for MMIX");
 }
 
-/* SETUP_INCOMING_VARARGS.  */
-
-void
-mmix_setup_incoming_varargs (args_so_farp, mode, vartype, pretend_sizep,
-                            second_time)
-     CUMULATIVE_ARGS * args_so_farp;
-     enum machine_mode mode;
-     tree vartype;
-     int * pretend_sizep;
-     int second_time ATTRIBUTE_UNUSED;
-{
-  /* For stdarg, the last named variable has been handled, but
-     args_so_farp has not been advanced for it.  For varargs, the current
-     argument is to be counted to the anonymous ones.  */
-  if (current_function_stdarg)
-    {
-      if (args_so_farp->regs + 1 < MMIX_MAX_ARGS_IN_REGS)
-       *pretend_sizep
-         = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8;
-    }
-  else if (current_function_varargs)
-    {
-      if (args_so_farp->regs < MMIX_MAX_ARGS_IN_REGS)
-       *pretend_sizep
-         = (MMIX_MAX_ARGS_IN_REGS - args_so_farp->regs) * 8;
-
-      /* For varargs, we get here when we see the last named parameter,
-        which will actually be passed on stack.  So make the next call
-        (there will be one) to FUNCTION_ARG return 0, to count it on
-        stack, so va_arg for it will get right.  FIXME: The GCC core
-        should provide TRT.  */
-      args_so_farp->now_varargs = 1;
-    }
-  else
-    internal_error ("neither varargs or stdarg in mmix_setup_incoming_varargs");
+/* Worker function for TARGET_SETUP_INCOMING_VARARGS.  For the moment,
+   let's stick to pushing argument registers on the stack.  Later, we
+   can parse all arguments in registers, to improve performance.  */
 
+static void
+mmix_setup_incoming_varargs (CUMULATIVE_ARGS *args_so_farp,
+                            enum machine_mode mode,
+                            tree vartype,
+                            int *pretend_sizep,
+                            int second_time ATTRIBUTE_UNUSED)
+{
+  /* The last named variable has been handled, but
+     args_so_farp has not been advanced for it.  */
+  if (args_so_farp->regs + 1 < MMIX_MAX_ARGS_IN_REGS)
+    *pretend_sizep = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8;
 
   /* We assume that one argument takes up one register here.  That should
-     be true until we start messing with multi-reg parameters.   */
+     be true until we start messing with multi-reg parameters.  */
   if ((7 + (MMIX_FUNCTION_ARG_SIZE (mode, vartype))) / 8 != 1)
     internal_error ("MMIX Internal: Last named vararg would not fit in a register");
 }
 
-/* EXPAND_BUILTIN_VA_ARG.  */
-
-/* This is modified from the "standard" implementation of va_arg: read the
-   value from the current (padded) address and increment by the (padded)
-   size.  The difference for MMIX is that if the type is
-   pass-by-reference, then perform an indirection.  */
-
-rtx
-mmix_expand_builtin_va_arg (valist, type)
-     tree valist;
-     tree type;
-{
-  tree ptr_size = size_int (BITS_PER_WORD / BITS_PER_UNIT);
-  tree addr_tree, type_size = NULL;
-  tree align, alignm1;
-  tree rounded_size;
-  rtx addr;
-
-  /* Compute the rounded size of the type.  */
-
-  /* Get AP.  */
-  addr_tree = valist;
-  align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
-  alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
-  if (type == error_mark_node
-      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
-      || TREE_OVERFLOW (type_size))
-    /* Presumably an error; the size isn't computable.  A message has
-       supposedly been emitted elsewhere.  */
-    rounded_size = size_zero_node;
-  else
-    rounded_size = fold (build (MULT_EXPR, sizetype,
-                               fold (build (TRUNC_DIV_EXPR, sizetype,
-                                            fold (build (PLUS_EXPR, sizetype,
-                                                         type_size, alignm1)),
-                                            align)),
-                               align));
-
- if (AGGREGATE_TYPE_P (type)
-     && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) < 8
-     && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) != 0)
-   {
-     /* Adjust for big-endian the location of aggregates passed in a
-       register, but where the aggregate is accessed in a shorter mode
-       than the natural register mode (i.e. it is accessed as SFmode(?),
-       SImode, HImode or QImode rather than DImode or DFmode(?)).  FIXME:
-       Or should we adjust the mode in which the aggregate is read, to be
-       a register size mode?  (Hum, nah, a small offset is generally
-       cheaper than a wider memory access on MMIX.)  */
-     addr_tree
-       = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-               size_int ((BITS_PER_WORD / BITS_PER_UNIT)
-                         - GET_MODE_UNIT_SIZE (TYPE_MODE (type))));
-   }
- else if (!integer_zerop (rounded_size))
-   {
-     if (!really_constant_p (type_size))
-       /* Varying-size types come in by reference.  */
-       addr_tree
-        = build1 (INDIRECT_REF, build_pointer_type (type), addr_tree);
-     else
-       {
-        /* If the size is less than a register, then we need to pad the
-           address by adding the difference.  */
-        tree addend
-          = fold (build (COND_EXPR, sizetype,
-                         fold (build (GT_EXPR, sizetype,
-                                      rounded_size,
-                                      align)),
-                         size_zero_node,
-                         fold (build (MINUS_EXPR, sizetype,
-                                      rounded_size,
-                                      type_size))));
-        tree addr_tree1
-          = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-                         addend));
-
-        /* If this type is larger than what fits in a register, then it
-           is passed by reference.  */
-        addr_tree
-          = fold (build (COND_EXPR, TREE_TYPE (addr_tree1),
-                         fold (build (GT_EXPR, sizetype,
-                                      rounded_size,
-                                      ptr_size)),
-                         build1 (INDIRECT_REF, build_pointer_type (type),
-                                 addr_tree1),
-                         addr_tree1));
-       }
-   }
-
-  addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
-  addr = copy_to_reg (addr);
-
-  if (!integer_zerop (rounded_size))
-    {
-      /* Compute new value for AP.  For MMIX, it is always advanced by the
-        size of a register.  */
-      tree t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-                     build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                            ptr_size));
-      TREE_SIDE_EFFECTS (t) = 1;
-      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-    }
-
-  return addr;
-}
-
 /* TRAMPOLINE_SIZE.  */
 /* Four 4-byte insns plus two 8-byte values.  */
 int mmix_trampoline_size = 32;
@@ -1426,8 +888,7 @@ int mmix_trampoline_size = 32;
 /* TRAMPOLINE_TEMPLATE.  */
 
 void
-mmix_trampoline_template (stream)
-     FILE * stream;
+mmix_trampoline_template (FILE *stream)
 {
   /* Read a value into the static-chain register and jump somewhere.  The
      static chain is stored at offset 16, and the function address is
@@ -1449,10 +910,7 @@ mmix_trampoline_template (stream)
    some day it will).  */
 
 void
-mmix_initialize_trampoline (trampaddr, fnaddr, static_chain)
-     rtx trampaddr;
-     rtx fnaddr;
-     rtx static_chain;
+mmix_initialize_trampoline (rtx trampaddr, rtx fnaddr, rtx static_chain)
 {
   emit_move_insn (gen_rtx_MEM (DImode, plus_constant (trampaddr, 16)),
                  static_chain);
@@ -1469,8 +927,7 @@ mmix_initialize_trampoline (trampaddr, fnaddr, static_chain)
    instruction, unless TARGET_BASE_ADDRESSES.  */
 
 int
-mmix_constant_address_p (x)
-     rtx x;
+mmix_constant_address_p (rtx x)
 {
   RTX_CODE code = GET_CODE (x);
   int addend = 0;
@@ -1483,7 +940,6 @@ mmix_constant_address_p (x)
     case SYMBOL_REF:
       return 1;
 
-    case CONSTANT_P_RTX:
     case HIGH:
       /* FIXME: Don't know how to dissect these.  Avoid them for now,
         except we know they're constants.  */
@@ -1533,10 +989,9 @@ mmix_constant_address_p (x)
    Used by GO_IF_LEGITIMATE_ADDRESS.  */
 
 int
-mmix_legitimate_address (mode, x, strict_checking)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx x;
-     int strict_checking;
+mmix_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED,
+                        rtx x,
+                        int strict_checking)
 {
 #define MMIX_REG_OK(X)                                                 \
   ((strict_checking                                                    \
@@ -1595,8 +1050,7 @@ mmix_legitimate_address (mode, x, strict_checking)
 /* LEGITIMATE_CONSTANT_P.  */
 
 int
-mmix_legitimate_constant_p (x)
-     rtx x;
+mmix_legitimate_constant_p (rtx x)
 {
   RTX_CODE code = GET_CODE (x);
 
@@ -1612,10 +1066,7 @@ mmix_legitimate_constant_p (x)
 /* SELECT_CC_MODE.  */
 
 enum machine_mode
-mmix_select_cc_mode (op, x, y)
-     RTX_CODE op;
-     rtx x;
-     rtx y ATTRIBUTE_UNUSED;
+mmix_select_cc_mode (RTX_CODE op, rtx x, rtx y ATTRIBUTE_UNUSED)
 {
   /* We use CCmode, CC_UNSmode, CC_FPmode, CC_FPEQmode and CC_FUNmode to
      output different compare insns.  Note that we do not check the
@@ -1642,48 +1093,33 @@ mmix_select_cc_mode (op, x, y)
 /* REVERSIBLE_CC_MODE.  */
 
 int
-mmix_reversible_cc_mode (mode)
-     enum machine_mode mode;
+mmix_reversible_cc_mode (enum machine_mode mode)
 {
   /* That is, all integer and the EQ, NE, ORDERED and UNORDERED float
      compares.  */
   return mode != CC_FPmode;
 }
 
-/* DEFAULT_RTX_COSTS.  */
+/* TARGET_RTX_COSTS.  */
 
-int
-mmix_rtx_cost_recalculated (x, code, outer_code, costp)
-     rtx x ATTRIBUTE_UNUSED;
-     RTX_CODE code ATTRIBUTE_UNUSED;
-     RTX_CODE outer_code ATTRIBUTE_UNUSED;
-     int *costp ATTRIBUTE_UNUSED;
+static bool
+mmix_rtx_costs (rtx x ATTRIBUTE_UNUSED,
+               int code ATTRIBUTE_UNUSED,
+               int outer_code ATTRIBUTE_UNUSED,
+               int *total ATTRIBUTE_UNUSED)
 {
   /* For the time being, this is just a stub and we'll accept the
      generic calculations, until we can do measurements, at least.
      Say we did not modify any calculated costs.  */
-  return 0;
-}
-
-/* ADDRESS_COST.  */
-
-int
-mmix_address_cost (addr)
-     rtx addr ATTRIBUTE_UNUSED;
-{
-  /* There's no difference in the address costs and we have lots of
-     registers.  Some targets use constant 0, many others use 1 to say
-     this.  Let's start with 1.  */
-  return 1;
+  return false;
 }
 
 /* REGISTER_MOVE_COST.  */
 
 int
-mmix_register_move_cost (mode, from, to)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     enum reg_class from;
-     enum reg_class to;
+mmix_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+                        enum reg_class from,
+                        enum reg_class to)
 {
   return (from == GENERAL_REGS && from == to) ? 2 : 3;
 }
@@ -1695,15 +1131,13 @@ mmix_register_move_cost (mode, from, to)
 /* DATA_SECTION_ASM_OP.  */
 
 const char *
-mmix_data_section_asm_op ()
+mmix_data_section_asm_op (void)
 {
   return "\t.data ! mmixal:= 8H LOC 9B";
 }
 
 static void
-mmix_encode_section_info (decl, first)
-     tree decl;
-     int first;
+mmix_encode_section_info (tree decl, rtx rtl, int first)
 {
   /* Test for an external declaration, and do nothing if it is one.  */
   if ((TREE_CODE (decl) == VAR_DECL
@@ -1722,16 +1156,16 @@ mmix_encode_section_info (decl, first)
         means that when -mtoplevel-symbols is in use, we can just handle
         well-behaved ISO-compliant code.  */
 
-      const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+      const char *str = XSTR (XEXP (rtl, 0), 0);
       int len = strlen (str);
       char *newstr;
 
       /* Why is the return type of ggc_alloc_string const?  */
-      newstr = (char *) ggc_alloc_string ("", len + 1);
+      newstr = CONST_CAST (char *, ggc_alloc_string ("", len + 1));
 
       strcpy (newstr + 1, str);
       *newstr = '@';
-      XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
+      XSTR (XEXP (rtl, 0), 0) = newstr;
     }
 
   /* Set SYMBOL_REF_FLAG for things that we want to access with GETA.  We
@@ -1744,16 +1178,11 @@ mmix_encode_section_info (decl, first)
          && !TREE_SIDE_EFFECTS (decl)
          && (!DECL_INITIAL (decl)
              || TREE_CONSTANT (DECL_INITIAL (decl)))))
-    {
-      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
-                 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
-      SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
-    }
+    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
 }
 
 static const char *
-mmix_strip_name_encoding (name)
-     const char *name;
+mmix_strip_name_encoding (const char *name)
 {
   for (; (*name == '@' || *name == '*'); name++)
     ;
@@ -1761,38 +1190,33 @@ mmix_strip_name_encoding (name)
   return name;
 }
 
-/* ASM_FILE_START.  */
+/* TARGET_ASM_FILE_START.
+   We just emit a little comment for the time being.  */
 
-void
-mmix_asm_file_start (stream)
-     FILE * stream;
+static void
+mmix_file_start (void)
 {
-  /* We just emit a little comment for the time being.  FIXME: Perhaps add
-     -mstandalone and some segment and prefix setup here.  */
-  ASM_OUTPUT_SOURCE_FILENAME (stream, main_input_filename);
+  default_file_start ();
 
-  fprintf (stream, "! mmixal:= 8H LOC Data_Section\n");
+  fputs ("! mmixal:= 8H LOC Data_Section\n", asm_out_file);
 
-  /* Make sure each file starts with the text section. */
-  text_section ();
+  /* Make sure each file starts with the text section.  */
+  switch_to_section (text_section);
 }
 
-/* ASM_FILE_END.  */
+/* TARGET_ASM_FILE_END.  */
 
-void
-mmix_asm_file_end (stream)
-     FILE * stream ATTRIBUTE_UNUSED;
+static void
+mmix_file_end (void)
 {
-  /* Make sure each file ends with the data section. */
-  data_section ();
+  /* Make sure each file ends with the data section.  */
+  switch_to_section (data_section);
 }
 
 /* ASM_OUTPUT_SOURCE_FILENAME.  */
 
 void
-mmix_asm_output_source_filename (stream, name)
-     FILE * stream;
-     const char * name;
+mmix_asm_output_source_filename (FILE *stream, const char *name)
 {
   fprintf (stream, "# 1 ");
   OUTPUT_QUOTED_STRING (stream, name);
@@ -1802,10 +1226,7 @@ mmix_asm_output_source_filename (stream, name)
 /* OUTPUT_QUOTED_STRING.  */
 
 void
-mmix_output_quoted_string (stream, string, length)
-     FILE * stream;
-     const char * string;
-     int length;
+mmix_output_quoted_string (FILE *stream, const char *string, int length)
 {
   const char * string_end = string + length;
   static const char *const unwanted_chars = "\"[]\\";
@@ -1846,27 +1267,12 @@ mmix_output_quoted_string (stream, string, length)
     }
 }
 
-/* ASM_OUTPUT_SOURCE_LINE.  */
-
-void
-mmix_asm_output_source_line  (stream, lineno)
-     FILE * stream;
-     int lineno;
-{
-  fprintf (stream, "# %d ", lineno);
-  OUTPUT_QUOTED_STRING (stream, main_input_filename);
-  fprintf (stream, "\n");
-}
-
 /* Target hook for assembling integer objects.  Use mmix_print_operand
    for WYDE and TETRA.  Use mmix_output_octa to output 8-byte
    CONST_DOUBLEs.  */
 
 static bool
-mmix_assemble_integer (x, size, aligned_p)
-     rtx x;
-     unsigned int size;
-     int aligned_p;
+mmix_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
   if (aligned_p)
     switch (size)
@@ -1913,11 +1319,10 @@ mmix_assemble_integer (x, size, aligned_p)
        return true;
 
       case 8:
-       if (GET_CODE (x) == CONST_DOUBLE)
-         /* We don't get here anymore for CONST_DOUBLE, because DImode
-            isn't expressed as CONST_DOUBLE, and DFmode is handled
-            elsewhere.  */
-         abort ();
+       /* We don't get here anymore for CONST_DOUBLE, because DImode
+          isn't expressed as CONST_DOUBLE, and DFmode is handled
+          elsewhere.  */
+       gcc_assert (GET_CODE (x) != CONST_DOUBLE);
        assemble_integer_with_op ("\tOCTA\t", x);
        return true;
       }
@@ -1927,10 +1332,7 @@ mmix_assemble_integer (x, size, aligned_p)
 /* ASM_OUTPUT_ASCII.  */
 
 void
-mmix_asm_output_ascii (stream, string, length)
-     FILE *stream;
-     const char *string;
-     int length;
+mmix_asm_output_ascii (FILE *stream, const char *string, int length)
 {
   while (length > 0)
     {
@@ -1946,11 +1348,10 @@ mmix_asm_output_ascii (stream, string, length)
 /* ASM_OUTPUT_ALIGNED_COMMON.  */
 
 void
-mmix_asm_output_aligned_common (stream, name, size, align)
-     FILE *stream;
-     const char *name;
-     int size;
-     int align;
+mmix_asm_output_aligned_common (FILE *stream,
+                               const char *name,
+                               int size,
+                               int align)
 {
   /* This is mostly the elfos.h one.  There doesn't seem to be a way to
      express this in a mmixal-compatible way.  */
@@ -1963,13 +1364,12 @@ mmix_asm_output_aligned_common (stream, name, size, align)
 /* ASM_OUTPUT_ALIGNED_LOCAL.  */
 
 void
-mmix_asm_output_aligned_local (stream, name, size, align)
-     FILE * stream;
-     const char * name;
-     int size;
-     int align;
+mmix_asm_output_aligned_local (FILE *stream,
+                              const char *name,
+                              int size,
+                              int align)
 {
-  data_section ();
+  switch_to_section (data_section);
 
   ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT));
   assemble_name (stream, name);
@@ -1979,56 +1379,48 @@ mmix_asm_output_aligned_local (stream, name, size, align)
 /* ASM_OUTPUT_LABEL.  */
 
 void
-mmix_asm_output_label (stream, name)
-     FILE *stream;
-     const char * name;
+mmix_asm_output_label (FILE *stream, const char *name)
 {
   assemble_name (stream, name);
   fprintf (stream, "\tIS @\n");
 }
 
-/* ASM_DECLARE_REGISTER_GLOBAL.  */
+/* ASM_OUTPUT_INTERNAL_LABEL.  */
 
 void
-mmix_asm_declare_register_global (stream, decl, regno, name)
-     FILE *stream ATTRIBUTE_UNUSED;
-     tree decl ATTRIBUTE_UNUSED;
-     int regno ATTRIBUTE_UNUSED;
-     const char *name ATTRIBUTE_UNUSED;
+mmix_asm_output_internal_label (FILE *stream, const char *name)
 {
-  /* Nothing to do here, but there *will* be, therefore the framework is
-     here.  */
+  assemble_name_raw (stream, name);
+  fprintf (stream, "\tIS @\n");
 }
 
-/* ASM_GLOBALIZE_LABEL.  */
+/* ASM_DECLARE_REGISTER_GLOBAL.  */
 
 void
-mmix_asm_globalize_label (stream, name)
-     FILE * stream ATTRIBUTE_UNUSED;
-     const char * name ATTRIBUTE_UNUSED;
+mmix_asm_declare_register_global (FILE *stream ATTRIBUTE_UNUSED,
+                                 tree decl ATTRIBUTE_UNUSED,
+                                 int regno ATTRIBUTE_UNUSED,
+                                 const char *name ATTRIBUTE_UNUSED)
 {
-  asm_fprintf (stream, "\t.global ");
-  assemble_name (stream, name);
-  putc ('\n', stream);
+  /* Nothing to do here, but there *will* be, therefore the framework is
+     here.  */
 }
 
 /* ASM_WEAKEN_LABEL.  */
 
 void
-mmix_asm_weaken_label (stream, name)
-     FILE * stream ATTRIBUTE_UNUSED;
-     const char * name ATTRIBUTE_UNUSED;
+mmix_asm_weaken_label (FILE *stream ATTRIBUTE_UNUSED,
+                      const char *name ATTRIBUTE_UNUSED)
 {
-  asm_fprintf (stream, "\t.weak ");
+  fprintf (stream, "\t.weak ");
   assemble_name (stream, name);
-  asm_fprintf (stream, " ! mmixal-incompatible\n");
+  fprintf (stream, " ! mmixal-incompatible\n");
 }
 
 /* MAKE_DECL_ONE_ONLY.  */
 
 void
-mmix_make_decl_one_only (decl)
-     tree decl;
+mmix_make_decl_one_only (tree decl)
 {
   DECL_WEAK (decl) = 1;
 }
@@ -2037,9 +1429,7 @@ mmix_make_decl_one_only (decl)
    Strip GCC's '*' and our own '@'.  No order is assumed.  */
 
 void
-mmix_asm_output_labelref (stream, name)
-     FILE *stream;
-     const char *name;
+mmix_asm_output_labelref (FILE *stream, const char *name)
 {
   int is_extern = 1;
 
@@ -2052,24 +1442,10 @@ mmix_asm_output_labelref (stream, name)
               name);
 }
 
-/* ASM_OUTPUT_INTERNAL_LABEL.  */
-
-void
-mmix_asm_output_internal_label (stream, name, num)
-     FILE * stream;
-     const char * name;
-     int num;
-{
-  fprintf (stream, "%s:%d\tIS @\n", name, num);
-}
-
 /* ASM_OUTPUT_DEF.  */
 
 void
-mmix_asm_output_def (stream, name, value)
-     FILE * stream;
-     const char * name;
-     const char * value;
+mmix_asm_output_def (FILE *stream, const char *name, const char *value)
 {
   assemble_name (stream, name);
   fprintf (stream, "\tIS ");
@@ -2077,30 +1453,10 @@ mmix_asm_output_def (stream, name, value)
   fputc ('\n', stream);
 }
 
-/* ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL.  */
-
-void
-mmix_asm_output_define_label_difference_symbol (stream, symbol, hi, lo)
-     FILE *stream;
-     const char *symbol;
-     const char *hi;
-     const char *lo;
-{
-  assemble_name (stream, symbol);
-  fprintf (stream, "\tIS\t");
-  assemble_name (stream, hi);
-  fputc ('-', stream);
-  assemble_name (stream, lo);
-  fprintf (stream, "\n");
-}
-
 /* PRINT_OPERAND.  */
 
 void
-mmix_print_operand (stream, x, code)
-     FILE * stream;
-     rtx x;
-     int code;
+mmix_print_operand (FILE *stream, rtx x, int code)
 {
   /* When we add support for different codes later, we can, when needed,
      drop through to the main handler with a modified operand.  */
@@ -2268,7 +1624,7 @@ mmix_print_operand (stream, x, code)
 
     default:
       /* Presumably there's a missing case above if we get here.  */
-      internal_error ("MMIX Internal: Missing `%c' case in mmix_print_operand", code);
+      internal_error ("MMIX Internal: Missing %qc case in mmix_print_operand", code);
     }
 
   switch (GET_CODE (modified_x))
@@ -2327,8 +1683,7 @@ mmix_print_operand (stream, x, code)
 /* PRINT_OPERAND_PUNCT_VALID_P.  */
 
 int
-mmix_print_operand_punct_valid_p (code)
-     int code ATTRIBUTE_UNUSED;
+mmix_print_operand_punct_valid_p (int code ATTRIBUTE_UNUSED)
 {
   /* A '+' is used for branch prediction, similar to other ports.  */
   return code == '+'
@@ -2339,9 +1694,7 @@ mmix_print_operand_punct_valid_p (code)
 /* PRINT_OPERAND_ADDRESS.  */
 
 void
-mmix_print_operand_address (stream, x)
-     FILE *stream;
-     rtx x;
+mmix_print_operand_address (FILE *stream, rtx x)
 {
   if (REG_P (x))
     {
@@ -2386,9 +1739,7 @@ mmix_print_operand_address (stream, x)
 /* ASM_OUTPUT_REG_PUSH.  */
 
 void
-mmix_asm_output_reg_push (stream, regno)
-     FILE * stream;
-     int regno;
+mmix_asm_output_reg_push (FILE *stream, int regno)
 {
   fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n",
           reg_names[MMIX_STACK_POINTER_REGNUM],
@@ -2400,9 +1751,7 @@ mmix_asm_output_reg_push (stream, regno)
 /* ASM_OUTPUT_REG_POP.  */
 
 void
-mmix_asm_output_reg_pop (stream, regno)
-     FILE * stream;
-     int regno;
+mmix_asm_output_reg_pop (FILE *stream, int regno)
 {
   fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n",
           reg_names[MMIX_OUTPUT_REGNO (regno)],
@@ -2413,11 +1762,10 @@ mmix_asm_output_reg_pop (stream, regno)
 /* ASM_OUTPUT_ADDR_DIFF_ELT.  */
 
 void
-mmix_asm_output_addr_diff_elt (stream, body, value, rel)
-     FILE *stream;
-     rtx body ATTRIBUTE_UNUSED;
-     int value;
-     int rel;
+mmix_asm_output_addr_diff_elt (FILE *stream,
+                              rtx body ATTRIBUTE_UNUSED,
+                              int value,
+                              int rel)
 {
   fprintf (stream, "\tTETRA L%d-L%d\n", value, rel);
 }
@@ -2425,9 +1773,7 @@ mmix_asm_output_addr_diff_elt (stream, body, value, rel)
 /* ASM_OUTPUT_ADDR_VEC_ELT.  */
 
 void
-mmix_asm_output_addr_vec_elt (stream, value)
-     FILE *stream;
-     int value;
+mmix_asm_output_addr_vec_elt (FILE *stream, int value)
 {
   fprintf (stream, "\tOCTA L:%d\n", value);
 }
@@ -2435,9 +1781,7 @@ mmix_asm_output_addr_vec_elt (stream, value)
 /* ASM_OUTPUT_SKIP.  */
 
 void
-mmix_asm_output_skip (stream, nbytes)
-     FILE *stream;
-     int nbytes;
+mmix_asm_output_skip (FILE *stream, int nbytes)
 {
   fprintf (stream, "\tLOC @+%d\n", nbytes);
 }
@@ -2445,9 +1789,7 @@ mmix_asm_output_skip (stream, nbytes)
 /* ASM_OUTPUT_ALIGN.  */
 
 void
-mmix_asm_output_align (stream, power)
-     FILE *stream;
-     int power;
+mmix_asm_output_align (FILE *stream, int power)
 {
   /* We need to record the needed alignment of this section in the object,
      so we have to output an alignment directive.  Use a .p2align (not
@@ -2462,8 +1804,7 @@ mmix_asm_output_align (stream, power)
 /* DBX_REGISTER_NUMBER.  */
 
 int
-mmix_dbx_register_number (regno)
-     int regno;
+mmix_dbx_register_number (int regno)
 {
   /* Adjust the register number to the one it will be output as, dammit.
      It'd be nice if we could check the assumption that we're filling a
@@ -2481,13 +1822,22 @@ mmix_dbx_register_number (regno)
 
 /* End of target macro support functions.
 
-   Now MMIX's own functions.  First the exported ones.  */
+   Now the MMIX port's own functions.  First the exported ones.  */
+
+/* Wrapper for get_hard_reg_initial_val since integrate.h isn't included
+   from insn-emit.c.  */
+
+rtx
+mmix_get_hard_reg_initial_val (enum machine_mode mode, int regno)
+{
+  return get_hard_reg_initial_val (mode, regno);
+}
 
-/* Non-zero when the function epilogue is simple enough that a single
-   "POP %d,0" should be used.  */
+/* Nonzero when the function epilogue is simple enough that a single
+   "POP %d,0" should be used even within the function.  */
 
 int
-mmix_use_simple_return ()
+mmix_use_simple_return (void)
 {
   int regno;
 
@@ -2505,7 +1855,7 @@ mmix_use_simple_return ()
     /* Note that we assume that the frame-pointer-register is one of these
        registers, in which case we don't count it here.  */
     if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-         && regs_ever_live[regno] && !call_used_regs[regno]))
+         && df_regs_ever_live_p (regno) && !call_used_regs[regno]))
        || IS_MMIX_EH_RETURN_DATA_REG (regno))
       return 0;
 
@@ -2520,6 +1870,356 @@ mmix_use_simple_return ()
   return stack_space_to_allocate == 0;
 }
 
+
+/* Expands the function prologue into RTX.  */
+
+void
+mmix_expand_prologue (void)
+{
+  HOST_WIDE_INT locals_size = get_frame_size ();
+  int regno;
+  HOST_WIDE_INT stack_space_to_allocate
+    = (current_function_outgoing_args_size
+       + current_function_pretend_args_size
+       + locals_size + 7) & ~7;
+  HOST_WIDE_INT offset = -8;
+
+  /* Add room needed to save global non-register-stack registers.  */
+  for (regno = 255;
+       regno >= MMIX_FIRST_GLOBAL_REGNUM;
+       regno--)
+    /* Note that we assume that the frame-pointer-register is one of these
+       registers, in which case we don't count it here.  */
+    if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+         && df_regs_ever_live_p (regno) && !call_used_regs[regno]))
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      stack_space_to_allocate += 8;
+
+  /* If we do have a frame-pointer, add room for it.  */
+  if (frame_pointer_needed)
+    stack_space_to_allocate += 8;
+
+  /* If we have a non-local label, we need to be able to unwind to it, so
+     store the current register stack pointer.  Also store the return
+     address if we do that.  */
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    stack_space_to_allocate += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    /* If we do have a saved return-address slot, add room for it.  */
+    stack_space_to_allocate += 8;
+
+  /* Make sure we don't get an unaligned stack.  */
+  if ((stack_space_to_allocate % 8) != 0)
+    internal_error ("stack frame not a multiple of 8 bytes: %wd",
+                   stack_space_to_allocate);
+
+  if (current_function_pretend_args_size)
+    {
+      int mmix_first_vararg_reg
+       = (MMIX_FIRST_INCOMING_ARG_REGNUM
+          + (MMIX_MAX_ARGS_IN_REGS
+             - current_function_pretend_args_size / 8));
+
+      for (regno
+            = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
+          regno >= mmix_first_vararg_reg;
+          regno--)
+       {
+         if (offset < 0)
+           {
+             HOST_WIDE_INT stack_chunk
+               = stack_space_to_allocate > (256 - 8)
+               ? (256 - 8) : stack_space_to_allocate;
+
+             mmix_emit_sp_add (-stack_chunk);
+             offset += stack_chunk;
+             stack_space_to_allocate -= stack_chunk;
+           }
+
+         /* These registers aren't actually saved (as in "will be
+            restored"), so don't tell DWARF2 they're saved.  */
+         emit_move_insn (gen_rtx_MEM (DImode,
+                                      plus_constant (stack_pointer_rtx,
+                                                     offset)),
+                         gen_rtx_REG (DImode, regno));
+         offset -= 8;
+       }
+    }
+
+  /* Store the frame-pointer.  */
+
+  if (frame_pointer_needed)
+    {
+      rtx insn;
+
+      if (offset < 0)
+       {
+         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
+         HOST_WIDE_INT stack_chunk
+           = stack_space_to_allocate > (256 - 8 - 8)
+           ? (256 - 8 - 8) : stack_space_to_allocate;
+
+         mmix_emit_sp_add (-stack_chunk);
+
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
+
+      insn = emit_move_insn (gen_rtx_MEM (DImode,
+                                         plus_constant (stack_pointer_rtx,
+                                                        offset)),
+                            hard_frame_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      insn = emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+                                   stack_pointer_rtx,
+                                   GEN_INT (offset + 8)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      offset -= 8;
+    }
+
+  if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    {
+      rtx tmpreg, retreg;
+      rtx insn;
+
+      /* Store the return-address, if one is needed on the stack.  We
+        usually store it in a register when needed, but that doesn't work
+        with -fexceptions.  */
+
+      if (offset < 0)
+       {
+         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
+         HOST_WIDE_INT stack_chunk
+           = stack_space_to_allocate > (256 - 8 - 8)
+           ? (256 - 8 - 8) : stack_space_to_allocate;
+
+         mmix_emit_sp_add (-stack_chunk);
+
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
+
+      tmpreg = gen_rtx_REG (DImode, 255);
+      retreg = gen_rtx_REG (DImode, MMIX_rJ_REGNUM);
+
+      /* Dwarf2 code is confused by the use of a temporary register for
+        storing the return address, so we have to express it as a note,
+        which we attach to the actual store insn.  */
+      emit_move_insn (tmpreg, retreg);
+
+      insn = emit_move_insn (gen_rtx_MEM (DImode,
+                                         plus_constant (stack_pointer_rtx,
+                                                        offset)),
+                            tmpreg);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      REG_NOTES (insn)
+       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                            gen_rtx_SET (VOIDmode,
+                                         gen_rtx_MEM (DImode,
+                                                      plus_constant (stack_pointer_rtx,
+                                                                     offset)),
+                                         retreg),
+                            REG_NOTES (insn));
+
+      offset -= 8;
+    }
+  else if (MMIX_CFUN_HAS_LANDING_PAD)
+    offset -= 8;
+
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    {
+      /* Store the register defining the numbering of local registers, so
+        we know how long to unwind the register stack.  */
+
+      if (offset < 0)
+       {
+         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
+         HOST_WIDE_INT stack_chunk
+           = stack_space_to_allocate > (256 - 8 - 8)
+           ? (256 - 8 - 8) : stack_space_to_allocate;
+
+         mmix_emit_sp_add (-stack_chunk);
+
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
+
+      /* We don't tell dwarf2 about this one; we just have it to unwind
+        the register stack at landing pads.  FIXME: It's a kludge because
+        we can't describe the effect of the PUSHJ and PUSHGO insns on the
+        register stack at the moment.  Best thing would be to handle it
+        like stack-pointer offsets.  Better: some hook into dwarf2out.c
+        to produce DW_CFA_expression:s that specify the increment of rO,
+        and unwind it at eh_return (preferred) or at the landing pad.
+        Then saves to $0..$G-1 could be specified through that register.  */
+
+      emit_move_insn (gen_rtx_REG (DImode, 255),
+                     gen_rtx_REG (DImode,
+                                  MMIX_rO_REGNUM));
+      emit_move_insn (gen_rtx_MEM (DImode,
+                                  plus_constant (stack_pointer_rtx, offset)),
+                     gen_rtx_REG (DImode, 255));
+      offset -= 8;
+    }
+
+  /* After the return-address and the frame-pointer, we have the local
+     variables.  They're the ones that may have an "unaligned" size.  */
+  offset -= (locals_size + 7) & ~7;
+
+  /* Now store all registers that are global, i.e. not saved by the
+     register file machinery.
+
+     It is assumed that the frame-pointer is one of these registers, so it
+     is explicitly excluded in the count.  */
+
+  for (regno = 255;
+       regno >= MMIX_FIRST_GLOBAL_REGNUM;
+       regno--)
+    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && df_regs_ever_live_p (regno) && ! call_used_regs[regno])
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      {
+       rtx insn;
+
+       if (offset < 0)
+         {
+           HOST_WIDE_INT stack_chunk
+             = (stack_space_to_allocate > (256 - offset - 8)
+                ? (256 - offset - 8) : stack_space_to_allocate);
+
+           mmix_emit_sp_add (-stack_chunk);
+           offset += stack_chunk;
+           stack_space_to_allocate -= stack_chunk;
+         }
+
+       insn = emit_move_insn (gen_rtx_MEM (DImode,
+                                           plus_constant (stack_pointer_rtx,
+                                                          offset)),
+                              gen_rtx_REG (DImode, regno));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       offset -= 8;
+      }
+
+  /* Finally, allocate room for outgoing args and local vars if room
+     wasn't allocated above.  */
+  if (stack_space_to_allocate)
+    mmix_emit_sp_add (-stack_space_to_allocate);
+}
+
+/* Expands the function epilogue into RTX.  */
+
+void
+mmix_expand_epilogue (void)
+{
+  HOST_WIDE_INT locals_size = get_frame_size ();
+  int regno;
+  HOST_WIDE_INT stack_space_to_deallocate
+    = (current_function_outgoing_args_size
+       + current_function_pretend_args_size
+       + locals_size + 7) & ~7;
+
+  /* The first address to access is beyond the outgoing_args area.  */
+  HOST_WIDE_INT offset = current_function_outgoing_args_size;
+
+  /* Add the space for global non-register-stack registers.
+     It is assumed that the frame-pointer register can be one of these
+     registers, in which case it is excluded from the count when needed.  */
+  for (regno = 255;
+       regno >= MMIX_FIRST_GLOBAL_REGNUM;
+       regno--)
+    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && df_regs_ever_live_p (regno) && !call_used_regs[regno])
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      stack_space_to_deallocate += 8;
+
+  /* Add in the space for register stack-pointer.  If so, always add room
+     for the saved PC.  */
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    stack_space_to_deallocate += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    /* If we have a saved return-address slot, add it in.  */
+    stack_space_to_deallocate += 8;
+
+  /* Add in the frame-pointer.  */
+  if (frame_pointer_needed)
+    stack_space_to_deallocate += 8;
+
+  /* Make sure we don't get an unaligned stack.  */
+  if ((stack_space_to_deallocate % 8) != 0)
+    internal_error ("stack frame not a multiple of octabyte: %wd",
+                   stack_space_to_deallocate);
+
+  /* We will add back small offsets to the stack pointer as we go.
+     First, we restore all registers that are global, i.e. not saved by
+     the register file machinery.  */
+
+  for (regno = MMIX_FIRST_GLOBAL_REGNUM;
+       regno <= 255;
+       regno++)
+    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && df_regs_ever_live_p (regno) && !call_used_regs[regno])
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      {
+       if (offset > 255)
+         {
+           mmix_emit_sp_add (offset);
+           stack_space_to_deallocate -= offset;
+           offset = 0;
+         }
+
+       emit_move_insn (gen_rtx_REG (DImode, regno),
+                       gen_rtx_MEM (DImode,
+                                    plus_constant (stack_pointer_rtx,
+                                                   offset)));
+       offset += 8;
+      }
+
+  /* Here is where the local variables were.  As in the prologue, they
+     might be of an unaligned size.  */
+  offset += (locals_size + 7) & ~7;
+
+  /* The saved register stack pointer is just below the frame-pointer
+     register.  We don't need to restore it "manually"; the POP
+     instruction does that.  */
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    offset += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    /* The return-address slot is just below the frame-pointer register.
+       We don't need to restore it because we don't really use it.  */
+    offset += 8;
+
+  /* Get back the old frame-pointer-value.  */
+  if (frame_pointer_needed)
+    {
+      if (offset > 255)
+       {
+         mmix_emit_sp_add (offset);
+
+         stack_space_to_deallocate -= offset;
+         offset = 0;
+       }
+
+      emit_move_insn (hard_frame_pointer_rtx,
+                     gen_rtx_MEM (DImode,
+                                  plus_constant (stack_pointer_rtx,
+                                                 offset)));
+      offset += 8;
+    }
+
+  /* We do not need to restore pretended incoming args, just add back
+     offset to sp.  */
+  if (stack_space_to_deallocate != 0)
+    mmix_emit_sp_add (stack_space_to_deallocate);
+
+  if (current_function_calls_eh_return)
+    /* Adjust the (normal) stack-pointer to that of the receiver.
+       FIXME: It would be nice if we could also adjust the register stack
+       here, but we need to express it through DWARF 2 too.  */
+    emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+                          gen_rtx_REG (DImode,
+                                       MMIX_EH_RETURN_STACKADJ_REGNUM)));
+}
+
 /* Output an optimal sequence for setting a register to a specific
    constant.  Used in an alternative for const_ints in movdi, and when
    using large stack-frame offsets.
@@ -2528,11 +2228,10 @@ mmix_use_simple_return ()
    first insn and after the last insn is wanted.  */
 
 void
-mmix_output_register_setting (stream, regno, value, do_begin_end)
-     FILE *stream;
-     int regno;
-     HOST_WIDEST_INT value;
-     int do_begin_end;
+mmix_output_register_setting (FILE *stream,
+                             int regno,
+                             HOST_WIDEST_INT value,
+                             int do_begin_end)
 {
   if (do_begin_end)
     fprintf (stream, "\t");
@@ -2640,8 +2339,7 @@ mmix_output_register_setting (stream, regno, value, do_begin_end)
    else return 0.  */
 
 int
-mmix_shiftable_wyde_value (value)
-     unsigned HOST_WIDEST_INT value;
+mmix_shiftable_wyde_value (unsigned HOST_WIDEST_INT value)
 {
   /* Shift by 16 bits per group, stop when we've found two groups with
      nonzero bits.  */
@@ -2664,162 +2362,12 @@ mmix_shiftable_wyde_value (value)
   return 1;
 }
 
-/* True if this is an address_operand or a symbolic operand.  */
-
-int
-mmix_symbolic_or_address_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
-    case CONST:
-      op = XEXP (op, 0);
-      if ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-          || GET_CODE (XEXP (op, 0)) == LABEL_REF)
-         && (GET_CODE (XEXP (op, 1)) == CONST_INT
-             || (GET_CODE (XEXP (op, 1)) == CONST_DOUBLE
-                 && GET_MODE (XEXP (op, 1)) == VOIDmode)))
-       return 1;
-      /* FALLTHROUGH */
-    default:
-      return address_operand (op, mode);
-    }
-}
-
-/* True if this is a register or CONST_INT (or CONST_DOUBLE for DImode).
-   We could narrow the value down with a couple of predicated, but that
-   doesn't seem to be worth it at the moment.  */
-
-int
-mmix_reg_or_constant_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return register_operand (op, mode)
-    || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
-    || GET_CODE (op) == CONST_INT;
-}
-
-/* True if this is a register with a condition-code mode.  */
-
-int
-mmix_reg_cc_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  return register_operand (op, mode)
-    && (mode == CCmode || mode == CC_UNSmode || mode == CC_FPmode
-       || mode == CC_FPEQmode || mode == CC_FUNmode);
-}
-
-/* True if this is a foldable comparison operator
-   - one where a the result of (compare:CC (reg) (const_int 0)) can be
-   replaced by (reg).  */
-
-int
-mmix_foldable_comparison_operator (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  RTX_CODE code = GET_CODE (op);
-
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
-    mode = GET_MODE (XEXP (op, 0));
-
-  return ((mode == CCmode || mode == DImode)
-         && (code == NE || code == EQ || code == GE || code == GT
-             || code == LE))
-    /* FIXME: This may be a stupid trick.  What happens when GCC wants to
-       reverse the condition?  Can it do that by itself?  Maybe it can
-       even reverse the condition to fit a foldable one in the first
-       place?  */
-    || (mode == CC_UNSmode && (code == GTU || code == LEU));
-}
-
-/* Like comparison_operator, but only true if this comparison operator is
-   applied to a valid mode.  Needed to avoid jump.c generating invalid
-   code with -ffast-math (gcc.dg/20001228-1.c).  */
-
-int
-mmix_comparison_operator (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  RTX_CODE code = GET_CODE (op);
-
-  /* Comparison operators usually don't have a mode, but let's try and get
-     one anyway for the day that changes.  */
-  if (mode == VOIDmode)
-    mode = GET_MODE (op);
-
-  /* Get the mode from the first operand if we don't have one.  */
-  if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
-    mode = GET_MODE (XEXP (op, 0));
-
-  /* FIXME: This needs to be kept in sync with the tables in
-     mmix_output_condition.  */
-  return
-    (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
-    || (mode == CC_FUNmode
-       && (code == ORDERED || code == UNORDERED))
-    || (mode == CC_FPmode
-       && (code == GT || code == LT))
-    || (mode == CC_FPEQmode
-       && (code == NE || code == EQ))
-    || (mode == CC_UNSmode
-       && (code == GEU || code == GTU || code == LEU || code == LTU))
-    || (mode == CCmode
-       && (code == NE || code == EQ || code == GE || code == GT
-           || code == LE || code == LT))
-    || (mode == DImode
-       && (code == NE || code == EQ || code == GE || code == GT
-           || code == LE || code == LT || code == LEU || code == GTU));
-}
-
-/* True if this is a register or 0 (int or float).  */
-
-int
-mmix_reg_or_0_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  /* FIXME: Is mode calculation necessary and correct?  */
-  return
-    op == CONST0_RTX (mode == VOIDmode ? GET_MODE (op) : mode)
-    || register_operand (op, mode);
-}
-
-/* True if this is a register or an int 0..255.  */
-
-int
-mmix_reg_or_8bit_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return register_operand (op, mode)
-    || (GET_CODE (op) == CONST_INT
-       && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
-}
-
 /* Returns zero if code and mode is not a valid condition from a
    compare-type insn.  Nonzero if it is.  The parameter op, if non-NULL,
    is the comparison of mode is CC-somethingmode.  */
 
 int
-mmix_valid_comparison (code, mode, op)
-     RTX_CODE code;
-     enum machine_mode mode;
-     rtx op;
+mmix_valid_comparison (RTX_CODE code, enum machine_mode mode, rtx op)
 {
   if (mode == VOIDmode && op != NULL_RTX)
     mode = GET_MODE (op);
@@ -2848,9 +2396,7 @@ mmix_valid_comparison (code, mode, op)
    NULL_RTX if this is not a valid comparison.  */
 
 rtx
-mmix_gen_compare_reg (code, x, y)
-     RTX_CODE code;
-     rtx x, y;
+mmix_gen_compare_reg (RTX_CODE code, rtx x, rtx y)
 {
   enum machine_mode ccmode = SELECT_CC_MODE (code, x, y);
   rtx cc_reg;
@@ -2884,14 +2430,54 @@ mmix_gen_compare_reg (code, x, y)
 
 /* Local (static) helper functions.  */
 
+static void
+mmix_emit_sp_add (HOST_WIDE_INT offset)
+{
+  rtx insn;
+
+  if (offset < 0)
+    {
+      /* Negative stack-pointer adjustments are allocations and appear in
+        the prologue only.  We mark them as frame-related so unwind and
+        debug info is properly emitted for them.  */
+      if (offset > -255)
+       insn = emit_insn (gen_adddi3 (stack_pointer_rtx,
+                                     stack_pointer_rtx,
+                                     GEN_INT (offset)));
+      else
+       {
+         rtx tmpr = gen_rtx_REG (DImode, 255);
+         RTX_FRAME_RELATED_P (emit_move_insn (tmpr, GEN_INT (offset))) = 1;
+         insn = emit_insn (gen_adddi3 (stack_pointer_rtx,
+                                       stack_pointer_rtx, tmpr));
+       }
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+  else
+    {
+      /* Positive adjustments are in the epilogue only.  Don't mark them
+        as "frame-related" for unwind info.  */
+      if (CONST_OK_FOR_LETTER_P (offset, 'L'))
+       emit_insn (gen_adddi3 (stack_pointer_rtx,
+                              stack_pointer_rtx,
+                              GEN_INT (offset)));
+      else
+       {
+         rtx tmpr = gen_rtx_REG (DImode, 255);
+         emit_move_insn (tmpr, GEN_INT (offset));
+         insn = emit_insn (gen_adddi3 (stack_pointer_rtx,
+                                       stack_pointer_rtx, tmpr));
+       }
+    }
+}
+
 /* Print operator suitable for doing something with a shiftable
    wyde.  The type of operator is passed as an asm output modifier.  */
 
 static void
-mmix_output_shiftvalue_op_from_str (stream, mainop, value)
-     FILE *stream;
-     const char *mainop;
-     HOST_WIDEST_INT value;
+mmix_output_shiftvalue_op_from_str (FILE *stream,
+                                   const char *mainop,
+                                   HOST_WIDEST_INT value)
 {
   static const char *const op_part[] = {"L", "ML", "MH", "H"};
   int i;
@@ -2922,10 +2508,7 @@ mmix_output_shiftvalue_op_from_str (stream, mainop, value)
 /* Print a 64-bit value, optionally prefixed by assembly pseudo.  */
 
 static void
-mmix_output_octa (stream, value, do_begin_end)
-     FILE *stream;
-     HOST_WIDEST_INT value;
-     int do_begin_end;
+mmix_output_octa (FILE *stream, HOST_WIDEST_INT value, int do_begin_end)
 {
   /* Snipped from final.c:output_addr_const.  We need to avoid the
      presumed universal "0x" prefix.  We can do it by replacing "0x" with
@@ -2959,9 +2542,7 @@ mmix_output_octa (stream, value, do_begin_end)
    be output with an operand).  */
 
 static void
-mmix_output_shifted_value (stream, value)
-     FILE * stream;
-     HOST_WIDEST_INT value;
+mmix_output_shifted_value (FILE *stream, HOST_WIDEST_INT value)
 {
   int i;
 
@@ -2973,13 +2554,13 @@ mmix_output_shifted_value (stream, value)
     }
 
   for (i = 0; i < 4; i++)
-  {
-    /* We know we're through when we find one-bits in the low 16 bits.  */
-    if (value & 0xffff)
     {
-      fprintf (stream, "#%x", (int) (value & 0xffff));
-      return;
-    }
+      /* We know we're through when we find one-bits in the low 16 bits.  */
+      if (value & 0xffff)
+       {
+         fprintf (stream, "#%x", (int) (value & 0xffff));
+         return;
+       }
 
     value >>= 16;
   }
@@ -2997,10 +2578,7 @@ mmix_output_shifted_value (stream, value)
    same as swapping the arguments).  */
 
 static void
-mmix_output_condition (stream, x, reversed)
-     FILE *stream;
-     rtx x;
-     int reversed;
+mmix_output_condition (FILE *stream, rtx x, int reversed)
 {
   struct cc_conv
   {
@@ -3017,12 +2595,12 @@ mmix_output_condition (stream, x, reversed)
   {
     enum machine_mode cc_mode;
 
-    /* Terminated with {NIL, NULL, NULL} */
+    /* Terminated with {UNKNOWN, NULL, NULL} */
     const struct cc_conv *const convs;
   };
 
 #undef CCEND
-#define CCEND {NIL, NULL, NULL}
+#define CCEND {UNKNOWN, NULL, NULL}
 
   static const struct cc_conv cc_fun_convs[]
     = {{ORDERED, "Z", "P"},
@@ -3080,7 +2658,7 @@ mmix_output_condition (stream, x, reversed)
     {
       if (mode == cc_convs[i].cc_mode)
        {
-         for (j = 0; cc_convs[i].convs[j].cc != NIL; j++)
+         for (j = 0; cc_convs[i].convs[j].cc != UNKNOWN; j++)
            if (cc == cc_convs[i].convs[j].cc)
              {
                const char *mmix_cc
@@ -3105,8 +2683,7 @@ mmix_output_condition (stream, x, reversed)
 /* Return the bit-value for a const_int or const_double.  */
 
 static HOST_WIDEST_INT
-mmix_intval (x)
-     rtx x;
+mmix_intval (rtx x)
 {
   unsigned HOST_WIDEST_INT retval;
 
@@ -3147,19 +2724,13 @@ mmix_intval (x)
 
          REAL_VALUE_TO_TARGET_DOUBLE (value, bits);
 
-         if (sizeof (long) < sizeof (HOST_WIDEST_INT))
-           {
-             retval = (unsigned long) bits[1] / 2;
-             retval *= 2;
-             retval |= (unsigned long) bits[1] & 1;
-             retval
-               |= (unsigned HOST_WIDEST_INT) bits[0]
-                 << (sizeof (bits[0]) * 8);
-           }
-         else
-           retval = (unsigned long) bits[1];
-
-         return retval;
+         /* The double cast is necessary to avoid getting the long
+            sign-extended to unsigned long long(!) when they're of
+            different size (usually 32-bit hosts).  */
+         return
+           ((unsigned HOST_WIDEST_INT) (unsigned long) bits[0]
+            << (unsigned HOST_WIDEST_INT) 32U)
+           | (unsigned HOST_WIDEST_INT) (unsigned long) bits[1];
        }
       else if (GET_MODE (x) == SFmode)
        {
@@ -3173,6 +2744,15 @@ mmix_intval (x)
   fatal_insn ("MMIX Internal: This is not a constant:", x);
 }
 
+/* Worker function for TARGET_STRUCT_VALUE_RTX.  */
+
+static rtx
+mmix_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+                      int incoming ATTRIBUTE_UNUSED)
+{
+  return gen_rtx_REG (Pmode, MMIX_STRUCT_VALUE_REGNUM);
+}
+
 /*
  * Local variables:
  * eval: (c-set-style "gnu")