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 5f9b4a8..a55b0dc 100644 (file)
@@ -1,26 +1,28 @@
 /* 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 GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -40,6 +42,7 @@ Boston, MA 02111-1307, USA.  */
 #include "integrate.h"
 #include "target.h"
 #include "target-def.h"
+#include "real.h"
 
 /* First some local helper definitions.  */
 #define MMIX_FIRST_GLOBAL_REGNUM 32
@@ -51,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             \
@@ -62,39 +75,67 @@ Boston, MA 02111-1307, USA.  */
       || EH_RETURN_DATA_REGNO (2) == REGNO     \
       || EH_RETURN_DATA_REGNO (3) == REGNO))
 
+/* For the default ABI, we rename registers at output-time to fill the gap
+   between the (statically partitioned) saved registers and call-clobbered
+   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.
+   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))
+
+/* The %d in "POP %d,0".  */
+#define MMIX_POP_ARGUMENT()                                            \
+ ((! TARGET_ABI_GNU                                                    \
+   && current_function_return_rtx != NULL                              \
+   && ! current_function_returns_struct)                               \
+  ? (GET_CODE (current_function_return_rtx) == PARALLEL                        \
+     ? GET_NUM_ELEM (XVEC (current_function_return_rtx, 0)) : 1)       \
+  : 0)
+
 /* The canonical saved comparison operands for non-cc0 machines, set in
    the compare expander.  */
 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.  */
 
-/* This is used in the prologue for what number to pass in a PUSHJ or
-   PUSHGO insn.  */
-static int mmix_highest_saved_stack_register;
-
 /* 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 void mmix_init_machine_status PARAMS ((struct function *));
-
-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.  */
@@ -115,9 +156,56 @@ 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
 
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO  mmix_encode_section_info
+#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.
@@ -126,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
@@ -135,42 +223,34 @@ 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;
     }
-
-  /* All other targets add GC roots from their override_options function,
-     so play along.  */
-  ggc_add_rtx_root (&mmix_compare_op0, 1);
-  ggc_add_rtx_root (&mmix_compare_op1, 1);
 }
 
 /* INIT_EXPANDERS.  */
 
 void
-mmix_init_expanders ()
+mmix_init_expanders (void)
 {
   init_machine_status = mmix_init_machine_status;
 }
 
 /* Set the per-function data.  */
 
-static void
-mmix_init_machine_status (f)
-     struct function *f;
+static struct machine_function *
+mmix_init_machine_status (void)
 {
-  f->machine = xcalloc (1, sizeof (struct machine_function));
+  return ggc_alloc_cleared (sizeof (struct machine_function));
 }
 
 /* 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;
@@ -181,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;
@@ -194,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;
@@ -207,7 +283,7 @@ mmix_local_alignment (type, basic_align)
 /* CONDITIONAL_REGISTER_USAGE.  */
 
 void
-mmix_conditional_register_usage ()
+mmix_conditional_register_usage (void)
 {
   int i;
 
@@ -221,13 +297,19 @@ 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;
+
+      /* "Unfix" the parameter registers.  */
+      for (i = MMIX_RESERVED_GNU_ARG_0_REGNUM;
+          i < MMIX_RESERVED_GNU_ARG_0_REGNUM + MMIX_MAX_ARGS_IN_REGS;
+          i++)
+       fixed_regs[i] = 0;
     }
 
   /* Step over the ":" in special register names.  */
@@ -237,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
@@ -254,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
@@ -267,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
@@ -284,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
@@ -303,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))
@@ -317,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;
 
@@ -334,14 +435,34 @@ mmix_extra_constraint (x, c, strict)
       ? strict_memory_address_p (Pmode, x)
       : memory_address_p (Pmode, x);
 
+  /* R asks whether x is to be loaded with GETA or something else.  Right
+     now, only a SYMBOL_REF and LABEL_REF can fit for
+     TARGET_BASE_ADDRESSES.
+
+     Only constant symbolic addresses apply.  With TARGET_BASE_ADDRESSES,
+     we just allow straight LABEL_REF or SYMBOL_REFs with SYMBOL_REF_FLAG
+     set right now; only function addresses and code labels.  If we change
+     to let SYMBOL_REF_FLAG be set on other symbols, we have to check
+     inside CONST expressions.  When TARGET_BASE_ADDRESSES is not in
+     effect, a "raw" constant check together with mmix_constant_address_p
+     is all that's needed; we want all constant addresses to be loaded
+     with GETA then.  */
+  if (c == 'R')
+    return
+      GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE
+      && mmix_constant_address_p (x)
+      && (! TARGET_BASE_ADDRESSES
+         || (GET_CODE (x) == LABEL_REF
+             || (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))));
+
   if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode)
     return 0;
 
   value = mmix_intval (x);
 
   /* We used to map Q->J, R->K, S->L, T->N, U->O, but we don't have to any
-     more ('U' taken for address_operand).  Some letters map outside of
-     CONST_INT, though; we still use 'S' and 'T'.  */
+     more ('U' taken for address_operand, 'R' similarly).  Some letters map
+     outside of CONST_INT, though; we still use 'S' and 'T'.  */
   if (c == 'S')
     return mmix_shiftable_wyde_value (value);
   else if (c == 'T')
@@ -352,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
@@ -365,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
@@ -382,13 +502,14 @@ 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
-       /* FIXME: Set frame_alias_set on the following.  */
+       /* FIXME: Set frame_alias_set on the following.  (Why?)
+         See mmix_initial_elimination_offset for the reason we can't use
+         get_hard_reg_initial_val for both.  Always using a stack slot
+         and not a register would be suboptimal.  */
        ? validize_mem (gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, -16)))
        : get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM))
     : NULL_RTX;
@@ -397,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.  */
 }
@@ -406,15 +527,16 @@ 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
     = (get_frame_size () + current_function_outgoing_args_size + 7) & ~7;
 
-  /* There is no actual difference between these two.  */
+  /* There is no actual offset between these two virtual values, but for
+     the frame-pointer, we have the old one in the stack position below
+     it, so the offset for the frame-pointer to the stack-pointer is one
+     octabyte larger.  */
   if (fromreg == MMIX_ARG_POINTER_REGNUM
       && toreg == MMIX_FRAME_POINTER_REGNUM)
     return 0;
@@ -444,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;
 
@@ -458,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)
@@ -483,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))
@@ -498,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;
@@ -532,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;
@@ -551,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
@@ -575,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;
@@ -595,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);
 }
@@ -603,1910 +734,1491 @@ 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 + 8 + 7) & ~7;
-  int offset = -8;
-  int empty_stack_frame
-    = (current_function_outgoing_args_size == 0
-       && locals_size == 0
-       && current_function_pretend_args_size == 0
-       && current_function_varargs == 0
-       && current_function_stdarg == 0);
-  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");
+  cfun->machine->in_prologue = 1;
+}
 
-  /* 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;
+/* Make a note that we've seen the end of the prologue.  */
 
-  /* If we do have a frame-pointer, add room for it.  */
-  if (frame_pointer_needed)
-    stack_space_to_allocate += 8;
+static void
+mmix_target_asm_function_end_prologue (FILE *stream ATTRIBUTE_UNUSED)
+{
+  cfun->machine->in_prologue = 0;
+}
 
-  /* 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;
+/* 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.  */
 
-  /* 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);
+static void
+mmix_reorg (void)
+{
+  int regno;
 
-  if (current_function_pretend_args_size)
+  /* We put the number of the highest saved register-file register in a
+     location convenient for the call-patterns to output.  Note that we
+     don't tell dwarf2 about these registers, since it can't restore them
+     anyway.  */
+  for (regno = MMIX_LAST_STACK_REGISTER_REGNUM;
+       regno >= 0;
+       regno--)
+    if ((df_regs_ever_live_p (regno) && !call_used_regs[regno])
+       || (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed))
+      break;
+
+  /* Regardless of whether they're saved (they might be just read), we
+     mustn't include registers that carry parameters.  We could scan the
+     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, 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)
     {
-      int mmix_first_vararg_reg
-       = (MMIX_FIRST_INCOMING_ARG_REGNUM
-          + (MMIX_MAX_ARGS_IN_REGS
-             - current_function_pretend_args_size / 8));
+      regno = current_function_args_info.regs - 1;
+
+      /* We don't want to let this cause us to go over the limit and make
+        incoming parameter registers be misnumbered and treating the last
+        parameter register and incoming return value register call-saved.
+        Stop things at the unmodified scheme.  */
+      if (regno > MMIX_RETURN_VALUE_REGNUM - 1)
+       regno = MMIX_RETURN_VALUE_REGNUM - 1;
+    }
 
-      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;
+  cfun->machine->highest_saved_stack_register = regno;
+}
 
-             fprintf (stream, "\tSUBU %s,%s,%d\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      stack_chunk);
+/* TARGET_ASM_FUNCTION_EPILOGUE.  */
 
-             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;
-                 dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                    cfa_offset);
-               }
-             offset += stack_chunk;
-             stack_space_to_allocate -= stack_chunk;
-           }
+static void
+mmix_target_asm_function_epilogue (FILE *stream,
+                                  HOST_WIDE_INT locals_size ATTRIBUTE_UNUSED)
+{
+  /* Emit an \n for readability of the generated assembly.  */
+  fputc ('\n', stream);
+}
 
-         fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  offset);
+/* TARGET_ASM_OUTPUT_MI_THUNK.  */
 
-         /* These registers aren't actually saved (as in "will be
-            restored"), so don't tell DWARF2 they're saved.  */
+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];
 
-         offset -= 8;
-       }
+  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
+    {
+      mmix_output_register_setting (stream, 255, delta, 1);
+      fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
     }
 
-  /* In any case, skip over the return-address slot.  FIXME: Not needed
-     now.  */
-  offset -= 8;
+  fprintf (stream, "\tJMP ");
+  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
+  fprintf (stream, "\n");
+}
 
-  /* Store the frame-pointer.  */
+/* FUNCTION_PROFILER.  */
 
-  if (frame_pointer_needed)
-    {
-      empty_stack_frame = 0;
+void
+mmix_function_profiler (FILE *stream ATTRIBUTE_UNUSED,
+                       int labelno ATTRIBUTE_UNUSED)
+{
+  sorry ("function_profiler support for MMIX");
+}
 
-      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;
+/* 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.  */
 
-         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;
-             dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                cfa_offset);
-           }
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-       }
+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;
 
-      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)
-       dwarf2out_reg_save ("", MMIX_FRAME_POINTER_REGNUM,
-                           -cfa_offset + offset);
+  /* We assume that one argument takes up one register here.  That should
+     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");
+}
 
-      offset -= 8;
-    }
+/* TRAMPOLINE_SIZE.  */
+/* Four 4-byte insns plus two 8-byte values.  */
+int mmix_trampoline_size = 32;
 
-  if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    {
-      /* Store the return-address, if one is needed on the stack.  */
-      empty_stack_frame = 0;
 
-      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;
+/* TRAMPOLINE_TEMPLATE.  */
 
-         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;
-             dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                cfa_offset);
-           }
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-       }
+void
+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
+     stored at offset 24.  */
+  /* FIXME: GCC copies this using *intsize* (tetra), when it should use
+     register size (octa).  */
+  fprintf (stream, "\tGETA $255,1F\n\t");
+  fprintf (stream, "LDOU %s,$255,0\n\t",
+          reg_names[MMIX_STATIC_CHAIN_REGNUM]);
+  fprintf (stream, "LDOU $255,$255,8\n\t");
+  fprintf (stream, "GO $255,$255,0\n");
+  fprintf (stream, "1H\tOCTA 0\n\t");
+  fprintf (stream, "OCTA 0\n");
+}
 
-      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;
+/* INITIALIZE_TRAMPOLINE.  */
+/* Set the static chain and function pointer field in the trampoline.
+   We also SYNCID here to be sure (doesn't matter in the simulator, but
+   some day it will).  */
 
-  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.  */
+void
+mmix_initialize_trampoline (rtx trampaddr, rtx fnaddr, rtx static_chain)
+{
+  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (trampaddr, 16)),
+                 static_chain);
+  emit_move_insn (gen_rtx_MEM (DImode,
+                              plus_constant (trampaddr, 24)),
+                 fnaddr);
+  emit_insn (gen_sync_icache (validize_mem (gen_rtx_MEM (DImode,
+                                                        trampaddr)),
+                             GEN_INT (mmix_trampoline_size - 1)));
+}
 
-      empty_stack_frame = 0;
+/* We must exclude constant addresses that have an increment that is not a
+   multiple of four bytes because of restrictions of the GETA
+   instruction, unless TARGET_BASE_ADDRESSES.  */
 
-      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;
+int
+mmix_constant_address_p (rtx x)
+{
+  RTX_CODE code = GET_CODE (x);
+  int addend = 0;
+  /* When using "base addresses", anything constant goes.  */
+  int constant_ok = TARGET_BASE_ADDRESSES != 0;
 
-         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;
+  switch (code)
+    {
+    case LABEL_REF:
+    case SYMBOL_REF:
+      return 1;
 
-         if (doing_dwarf)
-           {
-             cfa_offset += stack_chunk;
-             dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                cfa_offset);
-           }
-       }
+    case HIGH:
+      /* FIXME: Don't know how to dissect these.  Avoid them for now,
+        except we know they're constants.  */
+      return constant_ok;
 
-      /* 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.  */
+    case CONST_INT:
+      addend = INTVAL (x);
+      break;
 
-      fprintf (stream, "\tGET $255,rO\n\tSTOU $255,%s,%d\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM], offset);
+    case CONST_DOUBLE:
+      if (GET_MODE (x) != VOIDmode)
+       /* Strange that we got here.  FIXME: Check if we do.  */
+       return constant_ok;
+      addend = CONST_DOUBLE_LOW (x);
+      break;
 
-      offset -= 8;
-    }
+    case CONST:
+      /* Note that expressions with arithmetic on forward references don't
+        work in mmixal.  People using gcc assembly code with mmixal might
+        need to move arrays and such to before the point of use.  */
+      if (GET_CODE (XEXP (x, 0)) == PLUS)
+       {
+         rtx x0 = XEXP (XEXP (x, 0), 0);
+         rtx x1 = XEXP (XEXP (x, 0), 1);
 
-  /* 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;
+         if ((GET_CODE (x0) == SYMBOL_REF
+              || GET_CODE (x0) == LABEL_REF)
+             && (GET_CODE (x1) == CONST_INT
+                 || (GET_CODE (x1) == CONST_DOUBLE
+                     && GET_MODE (x1) == VOIDmode)))
+           addend = mmix_intval (x1);
+         else
+           return constant_ok;
+       }
+      else
+       return constant_ok;
+      break;
 
-  /* Now store all registers that are global, i.e. not saved by the
-     register file machinery.
+    default:
+      return 0;
+    }
 
-     It is assumed that the frame-pointer is one of these registers, so it
-     is explicitly excluded in the count.  */
+  return constant_ok || (addend & 3) == 0;
+}
 
-  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))
-      {
-       empty_stack_frame = 0;
+/* Return 1 if the address is OK, otherwise 0.
+   Used by GO_IF_LEGITIMATE_ADDRESS.  */
 
-       if (offset < 0)
-         {
-           int stack_chunk;
+int
+mmix_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED,
+                        rtx x,
+                        int strict_checking)
+{
+#define MMIX_REG_OK(X)                                                 \
+  ((strict_checking                                                    \
+    && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER                                \
+       || (reg_renumber[REGNO (X)] > 0                                 \
+           && reg_renumber[REGNO (X)] <= MMIX_LAST_GENERAL_REGISTER))) \
+   || (!strict_checking                                                        \
+       && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER                     \
+          || REGNO (X) >= FIRST_PSEUDO_REGISTER                        \
+          || REGNO (X) == ARG_POINTER_REGNUM)))
 
-           /* 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;
-                   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;
-                   dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                      cfa_offset);
-                 }
-             }
+  /* We only accept:
+     (mem reg)
+     (mem (plus reg reg))
+     (mem (plus reg 0..255)).
+     unless TARGET_BASE_ADDRESSES, in which case we accept all
+     (mem constant_address) too.  */
 
-           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;
-      }
+    /* (mem reg) */
+  if (REG_P (x) && MMIX_REG_OK (x))
+    return 1;
 
-  /* Finally, allocate room for local vars (if they weren't allocated for
-     above) and outgoing args.  This might be any number of bytes (well,
-     we assume it fits in a host-int).
-     Don't allocate (the return-address slot) if the stack frame is empty.  */
-  if (stack_space_to_allocate && ! empty_stack_frame)
+  if (GET_CODE(x) == PLUS)
     {
-      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]);
-       }
+      rtx x1 = XEXP (x, 0);
+      rtx x2 = XEXP (x, 1);
 
-      if (doing_dwarf)
+      /* Try swapping the order.  FIXME: Do we need this?  */
+      if (! REG_P (x1))
        {
-         cfa_offset += stack_space_to_allocate;
-         dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                            cfa_offset);
+         rtx tem = x1;
+         x1 = x2;
+         x2 = tem;
        }
-    }
 
-  /* We put the number of the highest saved register-file register in a
-     location convenient for the call-patterns to output.  Note that we
-     don't tell dwarf2 about these registers, since it can't restore them
-     anyway.  */
-  for (regno = MMIX_LAST_REGISTER_FILE_REGNUM;
-       regno >= 0;
-       regno--)
-    if ((regs_ever_live[regno] && !call_used_regs[regno])
-       || (regno == MMIX_FRAME_POINTER_REGNUM && frame_pointer_needed))
-      break;
+      /* (mem (plus (reg?) (?))) */
+      if (!REG_P (x1) || !MMIX_REG_OK (x1))
+       return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x);
 
-  mmix_highest_saved_stack_register = regno;
-
-  /* FIXME: Remove this when a corrected mmix version is released.
-
-     This kludge is a work-around for a presumed bug in the mmix simulator
-     (reported to knuth-bug), all versions up and including "Version of 14
-     October 2001".  When the circular register stack fills up, the parts
-     that would be overwritten need to be written to memory.  If the
-     "filling" instruction is a PUSHJ or PUSHGO, rL == 0 afterwards.  That
-     precise condition (rS == rO && rL == 0) is the same as for an empty
-     register stack, which means no more data is written to memory for
-     that round.  A hack is to remove the "&& L!=0" from "@<Increase
-     rL@>=" in mmix-sim.w: the register stack isn't empty under normal
-     circumstances, unless SAVE or UNSAVE is used, interrupts are enabled
-     or cases where rS == rO and rL is explicitly written to 0 as in
-     "PUT rL,0".
-
-     A workaround is to make sure PUSHJ or PUSHGO isn't filling up the
-     register stac.  This is accomplished if $16 or higher is written
-     before the function call.  This doesn't happen from a leaf functions
-     of course.  For the MMIXware ABI, this can't happen if all called
-     functions have parameters, because parameters start at $16.
-     Otherwise, and for the GNU ABI, if any register $16 and up is used,
-     we can see if it's mentioned before any function-call without
-     parameters.  This isn't too important; the bug will probably be fixed
-     soon and there's an option to not emit the work-around code.  The
-     call-with-parameters kludge wouldn't be there if it hadn't been for
-     it being left-over from a previous mmix version.
-
-     The actual code makes sure any register stack fill happens as early
-     as in the function prologue with a "SET $16,$16" (essentially a nop
-     except for the effects on the register stack).  */
-  if (TARGET_REG_STACK_FILL_BUG
-      && ((TARGET_ABI_GNU && !leaf_function_p ())
-         || (!TARGET_ABI_GNU
-             && cfun->machine->has_call_without_parameters)))
-    {
-      /* We don't have a specific macro or derivable expression for the
-        first non-call-saved register.  If we need it in other places
-        than here (which is temporary code anyway), such a macro should
-        be added.  */
-      int flush_regno
-       = TARGET_ABI_GNU ? mmix_highest_saved_stack_register + 2 : 16;
-
-      fprintf (stream, "\tSET %s,%s\n",
-              reg_names[flush_regno], reg_names[flush_regno]);
+      /* (mem (plus (reg) (reg?))) */
+      if (REG_P (x2) && MMIX_REG_OK (x2))
+       return 1;
+
+      /* (mem (plus (reg) (0..255?))) */
+      if (GET_CODE (x2) == CONST_INT
+         && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
+       return 1;
+
+      return 0;
     }
-}
 
-/* TARGET_ASM_FUNCTION_EPILOGUE.  */
+  return TARGET_BASE_ADDRESSES && mmix_constant_address_p (x);
+}
 
-void
-mmix_target_asm_function_epilogue (stream, locals_size)
-     FILE *stream;
-     HOST_WIDE_INT locals_size;
+/* LEGITIMATE_CONSTANT_P.  */
 
+int
+mmix_legitimate_constant_p (rtx x)
 {
-  int regno;
-  int stack_space_to_deallocate
-    = (current_function_outgoing_args_size
-       + current_function_pretend_args_size
-       + (int) locals_size + 8 + 7) & ~7;
+  RTX_CODE code = GET_CODE (x);
 
-  /* The assumption that locals_size fits in an int is asserted in
-     mmix_target_asm_function_prologue.  */
+  /* We must allow any number due to the way the cse passes works; if we
+     do not allow any number here, general_operand will fail, and insns
+     will fatally fail recognition instead of "softly".  */
+  if (code == CONST_INT || code == CONST_DOUBLE)
+    return 1;
 
-  /* The first address to access is beyond the outgoing_args area.  */
-  int offset = current_function_outgoing_args_size;
-  int empty_stack_frame
-    = (current_function_outgoing_args_size == 0
-       && locals_size == 0
-       && current_function_pretend_args_size == 0
-       && ! MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS
-       && ! MMIX_CFUN_HAS_LANDING_PAD);
+  return CONSTANT_ADDRESS_P (x);
+}
 
-  /* 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;
+/* SELECT_CC_MODE.  */
 
-  /* 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;
+enum machine_mode
+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
+     validity of the comparison here.  */
 
-  /* Add in the frame-pointer.  */
-  if (frame_pointer_needed)
-    stack_space_to_deallocate += 8;
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    {
+      if (op == ORDERED || op == UNORDERED || op == UNGE
+         || op == UNGT || op == UNLE || op == UNLT)
+       return CC_FUNmode;
 
-  /* 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);
+      if (op == EQ || op == NE)
+       return CC_FPEQmode;
 
-  /* 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.  */
+      return CC_FPmode;
+    }
 
-  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))
-      {
-       empty_stack_frame = 0;
+  if (op == GTU || op == LTU || op == GEU || op == LEU)
+    return CC_UNSmode;
 
-       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);
+  return CCmode;
+}
 
-           stack_space_to_deallocate -= offset;
-           offset = 0;
-         }
+/* REVERSIBLE_CC_MODE.  */
 
-       fprintf (stream, "\tLDOU %s,%s,%d\n",
-                reg_names[regno],
-                reg_names[MMIX_STACK_POINTER_REGNUM],
-                offset);
-       offset += 8;
-      }
+int
+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;
+}
 
-  /* Here is where the local variables were.  As in the prologue, they
-     might be of an unaligned size.  */
-  offset += (locals_size + 7) & ~7;
+/* TARGET_RTX_COSTS.  */
 
+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 false;
+}
 
-  /* 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;
+/* REGISTER_MOVE_COST.  */
 
-  /* Get back the old frame-pointer-value.  */
-  if (frame_pointer_needed)
-    {
-      empty_stack_frame = 0;
+int
+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;
+}
 
-      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);
+/* Note that we don't have a TEXT_SECTION_ASM_OP, because it has to be a
+   compile-time constant; it's used in an asm in crtstuff.c, compiled for
+   the target.  */
 
-         stack_space_to_deallocate -= offset;
-         offset = 0;
-       }
+/* DATA_SECTION_ASM_OP.  */
 
-      fprintf (stream, "\tLDOU %s,%s,%d\n",
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset);
-      offset += 8;
-    }
+const char *
+mmix_data_section_asm_op (void)
+{
+  return "\t.data ! mmixal:= 8H LOC 9B";
+}
 
-  /* Do not deallocate the return-address slot if the stack frame is
-     empty, because then it was never allocated.  */
-  if (! empty_stack_frame)
+static void
+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
+       && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl)))
+      || (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl)))
+    ;
+  else if (first && DECL_P (decl))
     {
-      /* 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
-       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]);
+      /* For non-visible declarations, add a "@" prefix, which we skip
+        when the label is output.  If the label does not have this
+        prefix, a ":" is output if -mtoplevel-symbols.
 
-  /* The extra \n is so we have a blank line between the assembly code of
-     separate functions.  */
-  fprintf (stream, "\tPOP %d,0\n\n",
-          (! TARGET_ABI_GNU
-           && current_function_return_rtx != NULL
-           && ! current_function_returns_struct)
-          ? (GET_CODE (current_function_return_rtx) == PARALLEL
-             ? GET_NUM_ELEM (XVEC (current_function_return_rtx, 0)) : 1)
-          : 0);
-}
+        Note that this does not work for data that is declared extern and
+        later defined as static.  If there's code in between, that code
+        will refer to the extern declaration, and vice versa.  This just
+        means that when -mtoplevel-symbols is in use, we can just handle
+        well-behaved ISO-compliant code.  */
 
-/* ASM_OUTPUT_MI_THUNK.  */
+      const char *str = XSTR (XEXP (rtl, 0), 0);
+      int len = strlen (str);
+      char *newstr;
 
-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];
+      /* Why is the return type of ggc_alloc_string const?  */
+      newstr = CONST_CAST (char *, ggc_alloc_string ("", len + 1));
 
-  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);
+      strcpy (newstr + 1, str);
+      *newstr = '@';
+      XSTR (XEXP (rtl, 0), 0) = newstr;
     }
 
-  fprintf (stream, "\tJMP ");
-  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
-  fprintf (stream, "\n");
+  /* Set SYMBOL_REF_FLAG for things that we want to access with GETA.  We
+     may need different options to reach for different things with GETA.
+     For now, functions and things we know or have been told are constant.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      || TREE_CONSTANT (decl)
+      || (TREE_CODE (decl) == VAR_DECL
+         && TREE_READONLY (decl)
+         && !TREE_SIDE_EFFECTS (decl)
+         && (!DECL_INITIAL (decl)
+             || TREE_CONSTANT (DECL_INITIAL (decl)))))
+    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
 }
 
-/* FUNCTION_PROFILER.  */
-
-void
-mmix_function_profiler (stream, labelno)
-     FILE *stream ATTRIBUTE_UNUSED;
-     int labelno ATTRIBUTE_UNUSED;
+static const char *
+mmix_strip_name_encoding (const char *name)
 {
-  sorry ("function_profiler support for MMIX");
+  for (; (*name == '@' || *name == '*'); name++)
+    ;
+
+  return name;
 }
 
-/* SETUP_INCOMING_VARARGS.  */
+/* TARGET_ASM_FILE_START.
+   We just emit a little comment for the time being.  */
 
-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");
-
-
-  /* We assume that one argument takes up one register here.  That should
-     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 addr_tree, t;
-  HOST_WIDE_INT align;
-  HOST_WIDE_INT rounded_size;
-  rtx addr;
-
-  /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
-
-  /* Get AP.  */
-  addr_tree = valist;
-
- 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,
-               build_int_2 ((BITS_PER_WORD / BITS_PER_UNIT)
-                            - GET_MODE_UNIT_SIZE (TYPE_MODE (type)), 0));
-   }
- else
-   {
-    HOST_WIDE_INT adj;
-    adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
-    if (rounded_size > align)
-      adj = rounded_size;
-
-    addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-                      build_int_2 (rounded_size - adj, 0));
-
-    /* If this type is larger than what fits in a register, then it is
-       passed by reference.  */
-    if (rounded_size > BITS_PER_WORD / BITS_PER_UNIT)
-      {
-       tree type_ptr = build_pointer_type (type);
-       addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
-      }
-  }
-
-  addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
-  addr = copy_to_reg (addr);
+static void
+mmix_file_start (void)
+{
+  default_file_start ();
 
-  /* Compute new value for AP.  For MMIX, it is always advanced by the
-     size of a register.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                   build_int_2 (BITS_PER_WORD / BITS_PER_UNIT, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  fputs ("! mmixal:= 8H LOC Data_Section\n", asm_out_file);
 
-  return addr;
+  /* Make sure each file starts with the text section.  */
+  switch_to_section (text_section);
 }
 
-/* TRAMPOLINE_SIZE.  */
-/* Four 4-byte insns plus two 8-byte values.  */
-int mmix_trampoline_size = 32;
-
-
-/* TRAMPOLINE_TEMPLATE.  */
+/* TARGET_ASM_FILE_END.  */
 
-void
-mmix_trampoline_template (stream)
-     FILE * stream;
+static void
+mmix_file_end (void)
 {
-  /* Read a value from to static-chain, jump somewhere.  The static chain
-     is stored at offset 16, and the function address is stored at offset
-     24.  */
-  /* FIXME: GCC copies this using *intsize* (tetra), when it should use
-     register size (octa).  */
-  fprintf (stream, "\tGETA $255,1F\n\t");
-  fprintf (stream, "LDOU %s,$255,0\n\t",
-          reg_names[MMIX_STATIC_CHAIN_REGNUM]);
-  fprintf (stream, "LDOU $255,$255,8\n\t");
-  fprintf (stream, "GO $255,$255,0\n");
-  fprintf (stream, "1H\tOCTA 0\n\t");
-  fprintf (stream, "OCTA 0\n");
+  /* Make sure each file ends with the data section.  */
+  switch_to_section (data_section);
 }
 
-/* INITIALIZE_TRAMPOLINE.  */
-/* Set the static chain and function pointer field in the trampoline.
-   We also SYNCID here to be sure (doesn't matter in the simulator, but
-   some day it will).  */
+/* ASM_OUTPUT_SOURCE_FILENAME.  */
 
 void
-mmix_initialize_trampoline (trampaddr, fnaddr, static_chain)
-     rtx trampaddr;
-     rtx fnaddr;
-     rtx static_chain;
+mmix_asm_output_source_filename (FILE *stream, const char *name)
 {
-  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (trampaddr, 16)),
-                 static_chain);
-  emit_move_insn (gen_rtx_MEM (DImode,
-                              plus_constant (trampaddr, 24)),
-                 fnaddr);
-  emit_insn (gen_sync_icache (validize_mem (gen_rtx_MEM (DImode,
-                                                        trampaddr)),
-                             GEN_INT (mmix_trampoline_size - 1)));
+  fprintf (stream, "# 1 ");
+  OUTPUT_QUOTED_STRING (stream, name);
+  fprintf (stream, "\n");
 }
 
-/* We must exclude constant addresses that have an increment that is not a
-   multiple of four bytes because of restrictions of the GETA
-   instruction.  FIXME: No, I don't think so.  Just add a constraint.  */
+/* OUTPUT_QUOTED_STRING.  */
 
-int
-mmix_constant_address_p (x)
-     rtx x;
+void
+mmix_output_quoted_string (FILE *stream, const char *string, int length)
 {
-  RTX_CODE code = GET_CODE (x);
-  int addend = 0;
-
-  if (code == LABEL_REF || code == SYMBOL_REF)
-    return 1;
-
-  if (code == CONSTANT_P_RTX || code == HIGH)
-    /* FIXME: Don't know how to dissect these.  Avoid them for now.  */
-    return 0;
+  const char * string_end = string + length;
+  static const char *const unwanted_chars = "\"[]\\";
 
-  switch (code)
+  /* Output "any character except newline and double quote character".  We
+     play it safe and avoid all control characters too.  We also do not
+     want [] as characters, should input be passed through m4 with [] as
+     quotes.  Further, we avoid "\", because the GAS port handles it as a
+     quoting character.  */
+  while (string < string_end)
     {
-    case LABEL_REF:
-    case SYMBOL_REF:
-      return 1;
-
-    case PLUS:
-      /* Can we get a naked PLUS? */
-    case CONSTANT_P_RTX:
-    case HIGH:
-      /* FIXME: Don't know how to dissect these.  Avoid them for now.  */
-      return 0;
-
-    case CONST_INT:
-      addend = INTVAL (x);
-      break;
-
-    case CONST_DOUBLE:
-      if (GET_MODE (x) != VOIDmode)
-       /* Strange that we got here.  FIXME: Check if we do.  */
-       return 0;
-      addend = CONST_DOUBLE_LOW (x);
-      break;
-
-    case CONST:
-      /* Note that expressions with arithmetic on forward references don't
-        work in mmixal.  People using gcc assembly code with mmixal might
-        need to move arrays and such to before the point of use.  */
-      if (GET_CODE (XEXP (x, 0)) == PLUS)
+      if (*string
+         && (unsigned char) *string < 128
+         && !ISCNTRL (*string)
+         && strchr (unwanted_chars, *string) == NULL)
        {
-         rtx x0 = XEXP (XEXP (x, 0), 0);
-         rtx x1 = XEXP (XEXP (x, 0), 1);
-
-         if ((GET_CODE (x0) == SYMBOL_REF
-              || GET_CODE (x0) == LABEL_REF)
-             && (GET_CODE (x1) == CONST_INT
-                 || (GET_CODE (x1) == CONST_DOUBLE
-                     && GET_MODE (x1) == VOIDmode)))
-           addend = mmix_intval (x1);
-         else
-           return 0;
+         fputc ('"', stream);
+         while (*string
+                && (unsigned char) *string < 128
+                && !ISCNTRL (*string)
+                && strchr (unwanted_chars, *string) == NULL
+                && string < string_end)
+           {
+             fputc (*string, stream);
+             string++;
+           }
+         fputc ('"', stream);
+         if (string < string_end)
+           fprintf (stream, ",");
+       }
+      if (string < string_end)
+       {
+         fprintf (stream, "#%x", *string & 255);
+         string++;
+         if (string < string_end)
+           fprintf (stream, ",");
        }
-      else
-       return 0;
-      break;
-
-    default:
-      return 0;
     }
-
-  return (addend & 3) == 0;
 }
 
-/* Return 1 if the address is OK, otherwise 0.
-   Used by GO_IF_LEGITIMATE_ADDRESS.  */
+/* Target hook for assembling integer objects.  Use mmix_print_operand
+   for WYDE and TETRA.  Use mmix_output_octa to output 8-byte
+   CONST_DOUBLEs.  */
 
-int
-mmix_legitimate_address (mode, x, strict_checking)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx x;
-     int strict_checking;
+static bool
+mmix_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
-#define MMIX_REG_OK(X)                                                 \
-  ((strict_checking                                                    \
-    && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER                                \
-       || (reg_renumber[REGNO (X)] > 0                                 \
-           && reg_renumber[REGNO (X)] <= MMIX_LAST_GENERAL_REGISTER))) \
-   || (!strict_checking                                                        \
-       && (REGNO (X) <= MMIX_LAST_GENERAL_REGISTER                     \
-          || REGNO (X) >= FIRST_PSEUDO_REGISTER                        \
-          || REGNO (X) == ARG_POINTER_REGNUM)))
+  if (aligned_p)
+    switch (size)
+      {
+       /* We handle a limited number of types of operands in here.  But
+          that's ok, because we can punt to generic functions.  We then
+          pretend that aligned data isn't needed, so the usual .<pseudo>
+          syntax is used (which works for aligned data too).  We actually
+          *must* do that, since we say we don't have simple aligned
+          pseudos, causing this function to be called.  We just try and
+          keep as much compatibility as possible with mmixal syntax for
+          normal cases (i.e. without GNU extensions and C only).  */
+      case 1:
+       if (GET_CODE (x) != CONST_INT)
+         {
+           aligned_p = 0;
+           break;
+         }
+       fputs ("\tBYTE\t", asm_out_file);
+       mmix_print_operand (asm_out_file, x, 'B');
+       fputc ('\n', asm_out_file);
+       return true;
 
-  /* We only accept:
-     (mem reg)
-     (mem (plus reg reg))
-     (mem (plus reg 0..255)).  */
+      case 2:
+       if (GET_CODE (x) != CONST_INT)
+         {
+           aligned_p = 0;
+           break;
+         }
+       fputs ("\tWYDE\t", asm_out_file);
+       mmix_print_operand (asm_out_file, x, 'W');
+       fputc ('\n', asm_out_file);
+       return true;
+
+      case 4:
+       if (GET_CODE (x) != CONST_INT)
+         {
+           aligned_p = 0;
+           break;
+         }
+       fputs ("\tTETRA\t", asm_out_file);
+       mmix_print_operand (asm_out_file, x, 'L');
+       fputc ('\n', asm_out_file);
+       return true;
 
+      case 8:
+       /* 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;
+      }
+  return default_assemble_integer (x, size, aligned_p);
+}
 
-    /* (mem reg) */
-  if (REG_P (x) && MMIX_REG_OK (x))
-    return 1;
+/* ASM_OUTPUT_ASCII.  */
 
-  if (GET_CODE(x) == PLUS)
+void
+mmix_asm_output_ascii (FILE *stream, const char *string, int length)
+{
+  while (length > 0)
     {
-      rtx x1 = XEXP (x, 0);
-      rtx x2 = XEXP (x, 1);
+      int chunk_size = length > 60 ? 60 : length;
+      fprintf (stream, "\tBYTE ");
+      mmix_output_quoted_string (stream, string, chunk_size);
+      string += chunk_size;
+      length -= chunk_size;
+      fprintf (stream, "\n");
+    }
+}
 
-      /* Try swapping the order.  FIXME: Do we need this?  */
-      if (! REG_P (x1))
-       {
-         rtx tem = x1;
-         x1 = x2;
-         x2 = tem;
-       }
+/* ASM_OUTPUT_ALIGNED_COMMON.  */
 
-      /* (mem (plus (reg) (?))) */
-      if (!REG_P (x1) || !MMIX_REG_OK (x1))
-       return 0;
+void
+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.  */
+  fprintf (stream, "\t.comm\t");
+  assemble_name (stream, name);
+  fprintf (stream, ",%u,%u ! mmixal-incompatible COMMON\n",
+          size, align / BITS_PER_UNIT);
+}
 
-      /* (mem (plus (reg) (reg))) */
-      if (REG_P (x2) && MMIX_REG_OK (x2))
-       return 1;
+/* ASM_OUTPUT_ALIGNED_LOCAL.  */
 
-      /* (mem (plus (reg) (0..255))) */
-      if (GET_CODE (x2) == CONST_INT
-         && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
-       return 1;
-    }
+void
+mmix_asm_output_aligned_local (FILE *stream,
+                              const char *name,
+                              int size,
+                              int align)
+{
+  switch_to_section (data_section);
 
-  return 0;
+  ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT));
+  assemble_name (stream, name);
+  fprintf (stream, "\tLOC @+%d\n", size);
 }
 
-/* LEGITIMATE_CONSTANT_P.  */
+/* ASM_OUTPUT_LABEL.  */
 
-int
-mmix_legitimate_constant_p (x)
-     rtx x;
+void
+mmix_asm_output_label (FILE *stream, const char *name)
 {
-  RTX_CODE code = GET_CODE (x);
+  assemble_name (stream, name);
+  fprintf (stream, "\tIS @\n");
+}
 
-  /* We must allow any number due to the way the cse passes works; if we
-     do not allow any number here, general_operand will fail, and insns
-     will fatally fail recognition instead of "softly".  */
-  if (code == CONST_INT || code == CONST_DOUBLE)
-    return 1;
+/* ASM_OUTPUT_INTERNAL_LABEL.  */
 
-  return CONSTANT_ADDRESS_P (x);
+void
+mmix_asm_output_internal_label (FILE *stream, const char *name)
+{
+  assemble_name_raw (stream, name);
+  fprintf (stream, "\tIS @\n");
 }
 
-/* SELECT_CC_MODE.  */
-
-enum machine_mode
-mmix_select_cc_mode (op, x, y)
-     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
-     validity of the comparison here.  */
-
-  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
-    {
-      if (op == ORDERED || op == UNORDERED || op == UNGE
-         || op == UNGT || op == UNLE || op == UNLT)
-       return CC_FUNmode;
-
-      if (op == EQ || op == NE)
-       return CC_FPEQmode;
-
-      return CC_FPmode;
-    }
-
-  if (op == GTU || op == LTU || op == GEU || op == LEU)
-    return CC_UNSmode;
-
-  return CCmode;
-}
-
-/* CANONICALIZE_COMPARISON.
-   FIXME: Check if the number adjustments trig.  */
+/* ASM_DECLARE_REGISTER_GLOBAL.  */
 
 void
-mmix_canonicalize_comparison (codep, op0p, op1p)
-     RTX_CODE * codep;
-     rtx * op0p ATTRIBUTE_UNUSED;
-     rtx * op1p;
-{
-  /* Change -1 to zero, if possible.  */
-  if ((*codep == LE || *codep == GT)
-      && GET_CODE (*op1p) == CONST_INT
-      && *op1p == constm1_rtx)
-    {
-      *codep = *codep == LE ? LT : GE;
-      *op1p = const0_rtx;
-    }
-
-  /* Fix up 256 to 255, if possible.  */
-  if ((*codep == LT || *codep == LTU || *codep == GE || *codep == GEU)
-      && GET_CODE (*op1p) == CONST_INT
-      && INTVAL (*op1p) == 256)
-    {
-      /* FIXME: Remove when I know this trigs.  */
-      fatal_insn ("oops, not debugged; fixing up value:", *op1p);
-      *codep = *codep == LT ? LE : *codep == LTU ? LEU : *codep
-       == GE ? GT : GTU;
-      *op1p = GEN_INT (255);
-    }
-}
-
-/* REVERSIBLE_CC_MODE.  */
-
-int
-mmix_reversible_cc_mode (mode)
-     enum machine_mode mode;
+mmix_asm_declare_register_global (FILE *stream ATTRIBUTE_UNUSED,
+                                 tree decl ATTRIBUTE_UNUSED,
+                                 int regno ATTRIBUTE_UNUSED,
+                                 const char *name ATTRIBUTE_UNUSED)
 {
-  /* That is, all integer and the EQ, NE, ORDERED and UNORDERED float
-     cmpares.  */
-  return mode != CC_FPmode;
+  /* Nothing to do here, but there *will* be, therefore the framework is
+     here.  */
 }
 
-/* DEFAULT_RTX_COSTS.  */
+/* ASM_WEAKEN_LABEL.  */
 
-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;
+void
+mmix_asm_weaken_label (FILE *stream ATTRIBUTE_UNUSED,
+                      const char *name 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;
+  fprintf (stream, "\t.weak ");
+  assemble_name (stream, name);
+  fprintf (stream, " ! mmixal-incompatible\n");
 }
 
-/* ADDRESS_COST.  */
+/* MAKE_DECL_ONE_ONLY.  */
 
-int
-mmix_address_cost (addr)
-     rtx addr ATTRIBUTE_UNUSED;
+void
+mmix_make_decl_one_only (tree decl)
 {
-  /* 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;
+  DECL_WEAK (decl) = 1;
 }
 
-/* REGISTER_MOVE_COST.  */
+/* ASM_OUTPUT_LABELREF.
+   Strip GCC's '*' and our own '@'.  No order is assumed.  */
 
-int
-mmix_register_move_cost (mode, from, to)
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     enum reg_class from;
-     enum reg_class to;
+void
+mmix_asm_output_labelref (FILE *stream, const char *name)
 {
-  return (from == GENERAL_REGS && from == to) ? 2 : 3;
-}
-
-/* Note that we don't have a TEXT_SECTION_ASM_OP, because it has to be a
-   compile-time constant; it's used in an asm in crtstuff.c, compiled for
-   the target.  */
+  int is_extern = 1;
 
-/* DATA_SECTION_ASM_OP.  */
+  for (; (*name == '@' || *name == '*'); name++)
+    if (*name == '@')
+      is_extern = 0;
 
-const char *
-mmix_data_section_asm_op ()
-{
-  return "\t.data ! mmixal:= 8H LOC 9B";
+  asm_fprintf (stream, "%s%U%s",
+              is_extern && TARGET_TOPLEVEL_SYMBOLS ? ":" : "",
+              name);
 }
 
-/* SELECT_SECTION.
-   The meat is from elfos.h, which we will eventually consider using.  */
+/* ASM_OUTPUT_DEF.  */
 
 void
-mmix_select_section (decl, reloc, align)
-     tree decl;
-     int reloc;
-     int align ATTRIBUTE_UNUSED;
+mmix_asm_output_def (FILE *stream, const char *name, const char *value)
 {
-  if (TREE_CODE (decl) == STRING_CST)
-    {
-      if (! flag_writable_strings)
-       const_section ();
-      else
-       data_section ();
-    }
-  else if (TREE_CODE (decl) == VAR_DECL)
-    {
-      if ((flag_pic && reloc)
-         || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
-         || !DECL_INITIAL (decl)
-         || (DECL_INITIAL (decl) != error_mark_node
-             && !TREE_CONSTANT (DECL_INITIAL (decl))))
-       data_section ();
-      else
-       const_section ();
-    }
-  else if (TREE_CODE (decl) == CONSTRUCTOR)
-    {
-      if ((flag_pic && reloc)
-         || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl)
-         || ! TREE_CONSTANT (decl))
-       data_section ();
-      else
-       const_section ();
-    }
-  else
-    const_section ();
+  assemble_name (stream, name);
+  fprintf (stream, "\tIS ");
+  assemble_name (stream, value);
+  fputc ('\n', stream);
 }
 
-/* ENCODE_SECTION_INFO.  */
+/* PRINT_OPERAND.  */
 
 void
-mmix_encode_section_info (decl)
-     tree decl;
+mmix_print_operand (FILE *stream, rtx x, int code)
 {
-  /* Test for an external declaration, and do nothing if it is one.  */
-  if ((TREE_CODE (decl) == VAR_DECL
-       && (DECL_EXTERNAL (decl) || TREE_PUBLIC (decl)))
-      || (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl)))
-    ;
-  else if (DECL_P (decl))
+  /* When we add support for different codes later, we can, when needed,
+     drop through to the main handler with a modified operand.  */
+  rtx modified_x = x;
+  int regno = x != NULL_RTX && REG_P (x) ? REGNO (x) : 0;
+
+  switch (code)
     {
-      /* For non-visible declarations, add a "@" prefix, which we skip
-        when the label is output.  If the label does not have this
-        prefix, a ":" is output.
+      /* Unrelated codes are in alphabetic order.  */
 
-        Note that this does not work for data that is declared extern and
-        later defined as static.  If there's code in between, that code
-        will refer to the extern declaration.  And vice versa.  Until we
-        can get rid of mmixal, we have to assume that code is
-        well-behaved.  */
+    case '+':
+      /* For conditional branches, output "P" for a probable branch.  */
+      if (TARGET_BRANCH_PREDICT)
+       {
+         x = find_reg_note (current_output_insn, REG_BR_PROB, 0);
+         if (x && INTVAL (XEXP (x, 0)) > REG_BR_PROB_BASE / 2)
+           putc ('P', stream);
+       }
+      return;
 
-      const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-      int len = strlen (str);
-      char *newstr;
+    case '.':
+      /* For the %d in POP %d,0.  */
+      fprintf (stream, "%d", MMIX_POP_ARGUMENT ());
+      return;
 
-      /* Doing as rs6000 seems safe; always use ggc.  Except don't copy
-        the suspected off-by-one bug.
-        FIXME: Is it still there? yes 2001-08-23
-        Why is the return type of ggc_alloc_string const?  */
-      newstr = (char *) ggc_alloc_string ("", len + 2);
+    case 'B':
+      if (GET_CODE (x) != CONST_INT)
+       fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
+      fprintf (stream, "%d", (int) (INTVAL (x) & 0xff));
+      return;
 
-      strcpy (newstr + 1, str);
-      *newstr = '@';
-      XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
-    }
+    case 'H':
+      /* Highpart.  Must be general register, and not the last one, as
+        that one cannot be part of a consecutive register pair.  */
+      if (regno > MMIX_LAST_GENERAL_REGISTER - 1)
+       internal_error ("MMIX Internal: Bad register: %d", regno);
 
-  /* FIXME: Later on, add SYMBOL_REF_FLAG for things that we can reach
-     from here via GETA, to check in LEGITIMATE_CONSTANT_P.  Needs to have
-     different options for the cases where we want *all* to be assumed
-     reachable via GETA, or all constant symbols, or just text symbols in
-     this file, or perhaps just the constant pool.  */
-}
+      /* This is big-endian, so the high-part is the first one.  */
+      fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno)]);
+      return;
 
-/* STRIP_NAME_ENCODING.  */
+    case 'L':
+      /* Lowpart.  Must be CONST_INT or general register, and not the last
+        one, as that one cannot be part of a consecutive register pair.  */
+      if (GET_CODE (x) == CONST_INT)
+       {
+         fprintf (stream, "#%lx",
+                  (unsigned long) (INTVAL (x)
+                                   & ((unsigned int) 0x7fffffff * 2 + 1)));
+         return;
+       }
 
-const char *
-mmix_strip_name_encoding (name)
-     const char *name;
-{
-  for (; (*name == '@' || *name == '*'); name++)
-    ;
+      if (GET_CODE (x) == SYMBOL_REF)
+       {
+         output_addr_const (stream, x);
+         return;
+       }
 
-  return name;
-}
+      if (regno > MMIX_LAST_GENERAL_REGISTER - 1)
+       internal_error ("MMIX Internal: Bad register: %d", regno);
 
-/* UNIQUE_SECTION.
-   The meat is from elfos.h, which we should consider using.  */
+      /* This is big-endian, so the low-part is + 1.  */
+      fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno) + 1]);
+      return;
 
-void
-mmix_unique_section (decl, reloc)
-     tree decl;
-     int reloc;
-{
-  int len;
-  int sec;
-  const char *name;
-  char *string;
-  const char *prefix;
-  static const char *const prefixes[4][2] =
-  {
-    { ".text.",   ".gnu.linkonce.t." },
-    { ".rodata.", ".gnu.linkonce.r." },
-    { ".data.",   ".gnu.linkonce.d." },
-    { ".bss.",    ".gnu.linkonce.b." }
-  };
+      /* Can't use 'a' because that's a generic modifier for address
+        output.  */
+    case 'A':
+      mmix_output_shiftvalue_op_from_str (stream, "ANDN",
+                                         ~(unsigned HOST_WIDEST_INT)
+                                         mmix_intval (x));
+      return;
 
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    sec = 0;
-  else if (DECL_INITIAL (decl) == 0
-          || DECL_INITIAL (decl) == error_mark_node)
-    sec =  3;
-  else if (DECL_READONLY_SECTION (decl, reloc))
-    sec = 1;
-  else
-    sec = 2;
+    case 'i':
+      mmix_output_shiftvalue_op_from_str (stream, "INC",
+                                         (unsigned HOST_WIDEST_INT)
+                                         mmix_intval (x));
+      return;
 
-  name   = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  /* Strip off any encoding in name.  */
-  STRIP_NAME_ENCODING (name, name);
-  prefix = prefixes[sec][DECL_ONE_ONLY (decl)];
-  len    = strlen (name) + strlen (prefix);
-  string = alloca (len + 1);
+    case 'o':
+      mmix_output_shiftvalue_op_from_str (stream, "OR",
+                                         (unsigned HOST_WIDEST_INT)
+                                         mmix_intval (x));
+      return;
 
-  sprintf (string, "%s%s", prefix, name);
+    case 's':
+      mmix_output_shiftvalue_op_from_str (stream, "SET",
+                                         (unsigned HOST_WIDEST_INT)
+                                         mmix_intval (x));
+      return;
 
-  DECL_SECTION_NAME (decl) = build_string (len, string);
-}
+    case 'd':
+    case 'D':
+      mmix_output_condition (stream, x, (code == 'D'));
+      return;
 
-/* ASM_FILE_START.  */
+    case 'e':
+      /* Output an extra "e" to make fcmpe, fune.  */
+      if (TARGET_FCMP_EPSILON)
+       fprintf (stream, "e");
+      return;
 
-void
-mmix_asm_file_start (stream)
-     FILE * stream;
-{
-  /* 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);
+    case 'm':
+      /* Output the number minus 1.  */
+      if (GET_CODE (x) != CONST_INT)
+       {
+         fatal_insn ("MMIX Internal: Bad value for 'm', not a CONST_INT",
+                     x);
+       }
+      fprintf (stream, HOST_WIDEST_INT_PRINT_DEC,
+              (HOST_WIDEST_INT) (mmix_intval (x) - 1));
+      return;
 
-  fprintf (stream, "! mmixal:= 8H LOC Data_Section\n");
+    case 'p':
+      /* Store the number of registers we want to save.  This was setup
+        by the prologue.  The actual operand contains the number of
+        registers to pass, but we don't use it currently.  Anyway, we
+        need to output the number of saved registers here.  */
+      fprintf (stream, "%d",
+              cfun->machine->highest_saved_stack_register + 1);
+      return;
 
-  /* Make sure each file starts with the text section. */
-  text_section ();
-}
+    case 'r':
+      /* Store the register to output a constant to.  */
+      if (! REG_P (x))
+       fatal_insn ("MMIX Internal: Expected a register, not this", x);
+      mmix_output_destination_register = MMIX_OUTPUT_REGNO (regno);
+      return;
 
-/* ASM_FILE_END.  */
+    case 'I':
+      /* Output the constant.  Note that we use this for floats as well.  */
+      if (GET_CODE (x) != CONST_INT
+         && (GET_CODE (x) != CONST_DOUBLE
+             || (GET_MODE (x) != VOIDmode && GET_MODE (x) != DFmode
+                 && GET_MODE (x) != SFmode)))
+       fatal_insn ("MMIX Internal: Expected a constant, not this", x);
+      mmix_output_register_setting (stream,
+                                   mmix_output_destination_register,
+                                   mmix_intval (x), 0);
+      return;
 
-void
-mmix_asm_file_end (stream)
-     FILE * stream ATTRIBUTE_UNUSED;
-{
-  /* Make sure each file ends with the data section. */
-  data_section ();
-}
+    case 'U':
+      /* An U for unsigned, if TARGET_ZERO_EXTEND.  Ignore the operand.  */
+      if (TARGET_ZERO_EXTEND)
+       putc ('U', stream);
+      return;
 
-/* ASM_IDENTIFY_GCC.  */
+    case 'v':
+      mmix_output_shifted_value (stream, (HOST_WIDEST_INT) mmix_intval (x));
+      return;
 
-void
-mmix_asm_identify_gcc (stream)
-     FILE * stream;
-{
-  /* No real need for the time being.  May be useful to GDB later on.  */
-  fprintf (stream, "# Compiled by GCC version %s\n",
-          version_string);
-}
+    case 'V':
+      mmix_output_shifted_value (stream, (HOST_WIDEST_INT) ~mmix_intval (x));
+      return;
 
-/* ASM_OUTPUT_SOURCE_FILENAME.  */
+    case 'W':
+      if (GET_CODE (x) != CONST_INT)
+       fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
+      fprintf (stream, "#%x", (int) (INTVAL (x) & 0xffff));
+      return;
 
-void
-mmix_asm_output_source_filename (stream, name)
-     FILE * stream;
-     const char * name;
-{
-  fprintf (stream, "# 1 ");
-  OUTPUT_QUOTED_STRING (stream, name);
-  fprintf (stream, "\n");
-}
+    case 0:
+      /* Nothing to do.  */
+      break;
 
-/* OUTPUT_QUOTED_STRING.  */
-
-void
-mmix_output_quoted_string (stream, string, length)
-     FILE * stream;
-     const char * string;
-     int length;
-{
-  const char * string_end = string + length;
-  static const char *const unwanted_chars = "\"[]\\";
+    default:
+      /* Presumably there's a missing case above if we get here.  */
+      internal_error ("MMIX Internal: Missing %qc case in mmix_print_operand", code);
+    }
 
-  /* Output "any character except newline and double quote character".  We
-     play it safe and avoid all control characters too.  We also do not
-     want [] as characters, should input be passed through m4 with [] as
-     quotes.  Further, we avoid "\", because the GAS port handles it as a
-     quoting character.  */
-  while (string < string_end)
+  switch (GET_CODE (modified_x))
     {
-      if (*string
-         && (unsigned char) *string < 128
-         && !ISCNTRL (*string)
-         && strchr (unwanted_chars, *string) == NULL)
-       {
-         fputc ('"', stream);
-         while (*string
-                && (unsigned char) *string < 128
-                && !ISCNTRL (*string)
-                && strchr (unwanted_chars, *string) == NULL
-                && string < string_end)
-           {
-             fputc (*string, stream);
-             string++;
-           }
-         fputc ('"', stream);
-         if (string < string_end)
-           fprintf (stream, ",");
-       }
-      if (string < string_end)
+    case REG:
+      regno = REGNO (modified_x);
+      if (regno >= FIRST_PSEUDO_REGISTER)
+       internal_error ("MMIX Internal: Bad register: %d", regno);
+      fprintf (stream, "%s", reg_names[MMIX_OUTPUT_REGNO (regno)]);
+      return;
+
+    case MEM:
+      output_address (XEXP (modified_x, 0));
+      return;
+
+    case CONST_INT:
+      /* For -2147483648, mmixal complains that the constant does not fit
+        in 4 bytes, so let's output it as hex.  Take care to handle hosts
+        where HOST_WIDE_INT is longer than an int.
+
+        Print small constants +-255 using decimal.  */
+
+      if (INTVAL (modified_x) > -256 && INTVAL (modified_x) < 256)
+       fprintf (stream, "%d", (int) (INTVAL (modified_x)));
+      else
+       fprintf (stream, "#%x",
+                (int) (INTVAL (modified_x)) & (unsigned int) ~0);
+      return;
+
+    case CONST_DOUBLE:
+      /* Do somewhat as CONST_INT.  */
+      mmix_output_octa (stream, mmix_intval (modified_x), 0);
+      return;
+
+    case CONST:
+      output_addr_const (stream, modified_x);
+      return;
+
+    default:
+      /* No need to test for all strange things.  Let output_addr_const do
+        it for us.  */
+      if (CONSTANT_P (modified_x)
+         /* Strangely enough, this is not included in CONSTANT_P.
+            FIXME: Ask/check about sanity here.  */
+         || GET_CODE (modified_x) == CODE_LABEL)
        {
-         fprintf (stream, "#%x", *string & 255);
-         string++;
-         if (string < string_end)
-           fprintf (stream, ",");
+         output_addr_const (stream, modified_x);
+         return;
        }
+
+      /* We need the original here.  */
+      fatal_insn ("MMIX Internal: Cannot decode this operand", x);
     }
 }
 
-/* ASM_OUTPUT_SOURCE_LINE.  */
+/* PRINT_OPERAND_PUNCT_VALID_P.  */
 
-void
-mmix_asm_output_source_line  (stream, lineno)
-     FILE * stream;
-     int lineno;
+int
+mmix_print_operand_punct_valid_p (int code ATTRIBUTE_UNUSED)
 {
-  fprintf (stream, "# %d ", lineno);
-  OUTPUT_QUOTED_STRING (stream, main_input_filename);
-  fprintf (stream, "\n");
+  /* A '+' is used for branch prediction, similar to other ports.  */
+  return code == '+'
+    /* A '.' is used for the %d in the POP %d,0 return insn.  */
+    || code == '.';
 }
 
-/* Target hook for assembling integer objects.  Use mmix_print_operand
-   for WYDE and TETRA.  Use mmix_output_octa to output 8-byte
-   CONST_DOUBLEs.  */
+/* PRINT_OPERAND_ADDRESS.  */
 
-static bool
-mmix_assemble_integer (x, size, aligned_p)
-     rtx x;
-     unsigned int size;
-     int aligned_p;
+void
+mmix_print_operand_address (FILE *stream, rtx x)
 {
-  if (aligned_p)
-    switch (size)
-      {
-      case 1:
-       fputs ("\tBYTE\t", asm_out_file);
-       mmix_print_operand (asm_out_file, x, 'B');
-       fputc ('\n', asm_out_file);
-       return true;
+  if (REG_P (x))
+    {
+      /* I find the generated assembly code harder to read without
+        the ",0".  */
+      fprintf (stream, "%s,0", reg_names[MMIX_OUTPUT_REGNO (REGNO (x))]);
+      return;
+    }
+  else if (GET_CODE (x) == PLUS)
+    {
+      rtx x1 = XEXP (x, 0);
+      rtx x2 = XEXP (x, 1);
 
-      case 2:
-       fputs ("\tWYDE\t", asm_out_file);
-       mmix_print_operand (asm_out_file, x, 'W');
-       fputc ('\n', asm_out_file);
-       return true;
+      if (REG_P (x1))
+       {
+         fprintf (stream, "%s,", reg_names[MMIX_OUTPUT_REGNO (REGNO (x1))]);
 
-      case 4:
-       fputs ("\tTETRA\t", asm_out_file);
-       mmix_print_operand (asm_out_file, x, 'L');
-       fputc ('\n', asm_out_file);
-       return true;
+         if (REG_P (x2))
+           {
+             fprintf (stream, "%s",
+                      reg_names[MMIX_OUTPUT_REGNO (REGNO (x2))]);
+             return;
+           }
+         else if (GET_CODE (x2) == CONST_INT
+                  && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
+           {
+             output_addr_const (stream, x2);
+             return;
+           }
+       }
+    }
 
-      case 8:
-       if (GET_CODE (x) == CONST_DOUBLE)
-         mmix_output_octa (asm_out_file, mmix_intval (x), 0);
-       else
-         assemble_integer_with_op ("\tOCTA\t", x);
-       return true;
-      }
-  return default_assemble_integer (x, size, aligned_p);
+  if (TARGET_BASE_ADDRESSES && mmix_legitimate_constant_p (x))
+    {
+      output_addr_const (stream, x);
+      return;
+    }
+
+  fatal_insn ("MMIX Internal: This is not a recognized address", x);
 }
 
-/* ASM_OUTPUT_ASCII.  */
+/* ASM_OUTPUT_REG_PUSH.  */
 
 void
-mmix_asm_output_ascii (stream, string, length)
-     FILE *stream;
-     const char *string;
-     int length;
+mmix_asm_output_reg_push (FILE *stream, int regno)
 {
-  while (length > 0)
-    {
-      int chunk_size = length > 60 ? 60 : length;
-      fprintf (stream, "\tBYTE ");
-      mmix_output_quoted_string (stream, string, chunk_size);
-      string += chunk_size;
-      length -= chunk_size;
-      fprintf (stream, "\n");
-    }
+  fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n",
+          reg_names[MMIX_STACK_POINTER_REGNUM],
+          reg_names[MMIX_STACK_POINTER_REGNUM],
+          reg_names[MMIX_OUTPUT_REGNO (regno)],
+          reg_names[MMIX_STACK_POINTER_REGNUM]);
 }
 
-/* ASM_OUTPUT_ALIGNED_COMMON.  */
+/* ASM_OUTPUT_REG_POP.  */
 
 void
-mmix_asm_output_aligned_common (stream, name, size, align)
-     FILE *stream;
-     const char *name;
-     int size;
-     int align;
+mmix_asm_output_reg_pop (FILE *stream, int regno)
 {
-  /* This is mostly the elfos.h one.  There doesn't seem to be a way to
-     express this in a mmixal-compatible way.  */
-  fprintf (stream, "\t.comm\t");
-  assemble_name (stream, name);
-  fprintf (stream, ",%u,%u ! mmixal-incompatible COMMON\n",
-          size, align / BITS_PER_UNIT);
+  fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n",
+          reg_names[MMIX_OUTPUT_REGNO (regno)],
+          reg_names[MMIX_STACK_POINTER_REGNUM],
+          reg_names[MMIX_STACK_POINTER_REGNUM]);
 }
 
-/* ASM_OUTPUT_ALIGNED_LOCAL.  */
+/* ASM_OUTPUT_ADDR_DIFF_ELT.  */
 
 void
-mmix_asm_output_aligned_local (stream, name, size, align)
-     FILE * stream;
-     const char * name;
-     int size;
-     int align;
+mmix_asm_output_addr_diff_elt (FILE *stream,
+                              rtx body ATTRIBUTE_UNUSED,
+                              int value,
+                              int rel)
 {
-  data_section ();
-
-  ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT));
-  assemble_name (stream, name);
-  fprintf (stream, "\tLOC @+%d\n", size);
+  fprintf (stream, "\tTETRA L%d-L%d\n", value, rel);
 }
 
-/* ASM_OUTPUT_LABEL.  */
+/* ASM_OUTPUT_ADDR_VEC_ELT.  */
 
 void
-mmix_asm_output_label (stream, name)
-     FILE *stream;
-     const char * name;
+mmix_asm_output_addr_vec_elt (FILE *stream, int value)
 {
-  assemble_name (stream, name);
-  fprintf (stream, "\tIS @\n");
+  fprintf (stream, "\tOCTA L:%d\n", value);
 }
 
-/* ASM_DECLARE_REGISTER_GLOBAL.  */
+/* ASM_OUTPUT_SKIP.  */
 
 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_skip (FILE *stream, int nbytes)
 {
-  /* Nothing to do here, but there *will* be, therefore the framework is
-     here.  */
+  fprintf (stream, "\tLOC @+%d\n", nbytes);
 }
 
-/* ASM_GLOBALIZE_LABEL.  */
+/* ASM_OUTPUT_ALIGN.  */
 
 void
-mmix_asm_globalize_label (stream, name)
-     FILE * stream ATTRIBUTE_UNUSED;
-     const char * name ATTRIBUTE_UNUSED;
+mmix_asm_output_align (FILE *stream, int power)
 {
-  asm_fprintf (stream, "\t.global ");
-  assemble_name (stream, name);
-  putc ('\n', stream);
+  /* 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
+     .align) so people will never have to wonder about whether the
+     argument is in number of bytes or the log2 thereof.  We do it in
+     addition to the LOC directive, so nothing needs tweaking when
+     copy-pasting assembly into mmixal.  */
+ fprintf (stream, "\t.p2align %d\n", power);
+ fprintf (stream, "\tLOC @+(%d-@)&%d\n", 1 << power, (1 << power) - 1);
 }
 
-/* ASM_WEAKEN_LABEL.  */
+/* DBX_REGISTER_NUMBER.  */
 
-void
-mmix_asm_weaken_label (stream, name)
-     FILE * stream ATTRIBUTE_UNUSED;
-     const char * name ATTRIBUTE_UNUSED;
+int
+mmix_dbx_register_number (int regno)
 {
-  asm_fprintf (stream, "\t.weak ");
-  assemble_name (stream, name);
-  asm_fprintf (stream, " ! mmixal-incompatible\n");
+  /* 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
+     gap, but every register between the last saved register and parameter
+     registers might be a valid parameter register.  */
+  regno = MMIX_OUTPUT_REGNO (regno);
+
+  /* We need to renumber registers to get the number of the return address
+     register in the range 0..255.  It is also space-saving if registers
+     mentioned in the call-frame information (which uses this function by
+     defaulting DWARF_FRAME_REGNUM to DBX_REGISTER_NUMBER) are numbered
+     0 .. 63.  So map 224 .. 256+15 -> 0 .. 47 and 0 .. 223 -> 48..223+48.  */
+  return regno >= 224 ? (regno - 224) : (regno + 48);
 }
 
-/* MAKE_DECL_ONE_ONLY.  */
+/* End of target macro support functions.
 
-void
-mmix_make_decl_one_only (decl)
-     tree decl;
+   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)
 {
-  DECL_WEAK (decl) = 1;
+  return get_hard_reg_initial_val (mode, regno);
 }
 
-/* ASM_OUTPUT_LABELREF.
-   Strip GCC's '*' and our own '@'.  No order is assumed.  */
+/* Nonzero when the function epilogue is simple enough that a single
+   "POP %d,0" should be used even within the function.  */
 
-void
-mmix_asm_output_labelref (stream, name)
-     FILE *stream;
-     const char *name;
+int
+mmix_use_simple_return (void)
 {
-  int is_extern = 1;
+  int regno;
 
-  for (; (*name == '@' || *name == '*'); name++)
-    if (*name == '@')
-      is_extern = 0;
+  int stack_space_to_allocate
+    = (current_function_outgoing_args_size
+       + current_function_pretend_args_size
+       + get_frame_size () + 7) & ~7;
 
-  asm_fprintf (stream, "%s%U%s",
-              is_extern && TARGET_TOPLEVEL_SYMBOLS ? ":" : "",
-              name);
-}
+  if (!TARGET_USE_RETURN_INSN || !reload_completed)
+    return 0;
 
-/* ASM_OUTPUT_INTERNAL_LABEL.  */
+  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))
+      return 0;
 
-void
-mmix_asm_output_internal_label (stream, name, num)
-     FILE * stream;
-     const char * name;
-     int num;
-{
-  fprintf (stream, "%s:%d\tIS @\n", name, num);
+  if (frame_pointer_needed)
+    stack_space_to_allocate += 8;
+
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    stack_space_to_allocate += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    stack_space_to_allocate += 8;
+
+  return stack_space_to_allocate == 0;
 }
 
-/* ASM_OUTPUT_DEF.  */
+
+/* Expands the function prologue into RTX.  */
 
 void
-mmix_asm_output_def (stream, name, value)
-     FILE * stream;
-     const char * name;
-     const char * value;
+mmix_expand_prologue (void)
 {
-  assemble_name (stream, name);
-  fprintf (stream, "\tIS ");
-  assemble_name (stream, value);
-  fputc ('\n', stream);
-}
+  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;
 
-/* ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL.  */
+  /* 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;
 
-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");
-}
+  /* If we do have a frame-pointer, add room for it.  */
+  if (frame_pointer_needed)
+    stack_space_to_allocate += 8;
 
-/* PRINT_OPERAND.  */
+  /* 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;
 
-void
-mmix_print_operand (stream, x, code)
-     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.  */
-  rtx modified_x = x;
+  /* 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);
 
-  switch (code)
+  if (current_function_pretend_args_size)
     {
-      /* Unrelated codes are in alphabetic order.  */
+      int mmix_first_vararg_reg
+       = (MMIX_FIRST_INCOMING_ARG_REGNUM
+          + (MMIX_MAX_ARGS_IN_REGS
+             - current_function_pretend_args_size / 8));
 
-    case '+':
-      /* For conditional branches, output "P" for a probable branch.  */
-      if (TARGET_BRANCH_PREDICT)
+      for (regno
+            = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
+          regno >= mmix_first_vararg_reg;
+          regno--)
        {
-         x = find_reg_note (current_output_insn, REG_BR_PROB, 0);
-         if (x && INTVAL (XEXP (x, 0)) > REG_BR_PROB_BASE / 2)
-           putc ('P', stream);
-       }
-      return;
-
-    case 'B':
-      if (GET_CODE (x) != CONST_INT)
-       fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
-      fprintf (stream, "%d", (int) (INTVAL (x) & 0xff));
-      return;
-
-    case 'H':
-      /* Highpart.  Must be general register, and not the last one, as
-        that one cannot be part of a consecutive register pair.  */
-      if (REGNO (x) > MMIX_LAST_GENERAL_REGISTER - 1)
-       internal_error ("MMIX Internal: Bad register: %d", REGNO (x));
-
-      /* This is big-endian, so the high-part is the first one.  */
-      fprintf (stream, "%s", reg_names[REGNO (x)]);
-      return;
+         if (offset < 0)
+           {
+             HOST_WIDE_INT stack_chunk
+               = stack_space_to_allocate > (256 - 8)
+               ? (256 - 8) : stack_space_to_allocate;
 
-    case 'L':
-      /* Lowpart.  Must be CONST_INT or general register, and not the last
-        one, as that one cannot be part of a consecutive register pair.  */
-      if (GET_CODE (x) == CONST_INT)
-       {
-         fprintf (stream, "#%lx",
-                  (unsigned long) (INTVAL (x)
-                                   & ((unsigned int) 0x7fffffff * 2 + 1)));
-         return;
-       }
+             mmix_emit_sp_add (-stack_chunk);
+             offset += stack_chunk;
+             stack_space_to_allocate -= stack_chunk;
+           }
 
-      if (GET_CODE (x) == SYMBOL_REF)
-       {
-         output_addr_const (stream, x);
-         return;
+         /* 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;
        }
+    }
 
-      if (REGNO (x) > MMIX_LAST_GENERAL_REGISTER - 1)
-       internal_error ("MMIX Internal: Bad register: %d", REGNO (x));
-
-      /* This is big-endian, so the low-part is + 1.  */
-      fprintf (stream, "%s", reg_names[REGNO (x) + 1]);
-      return;
-
-      /* Can't use 'a' because that's a generic modifier for address
-        output.  */
-    case 'A':
-      mmix_output_shiftvalue_op_from_str (stream, "ANDN",
-                                         ~(unsigned HOST_WIDEST_INT)
-                                         mmix_intval (x));
-      return;
-
-    case 'i':
-      mmix_output_shiftvalue_op_from_str (stream, "INC",
-                                         (unsigned HOST_WIDEST_INT)
-                                         mmix_intval (x));
-      return;
-
-    case 'o':
-      mmix_output_shiftvalue_op_from_str (stream, "OR",
-                                         (unsigned HOST_WIDEST_INT)
-                                         mmix_intval (x));
-      return;
+  /* Store the frame-pointer.  */
 
-    case 's':
-      mmix_output_shiftvalue_op_from_str (stream, "SET",
-                                         (unsigned HOST_WIDEST_INT)
-                                         mmix_intval (x));
-      return;
+  if (frame_pointer_needed)
+    {
+      rtx insn;
 
-    case 'd':
-    case 'D':
-      mmix_output_condition (stream, x, (code == 'D'));
-      return;
+      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;
 
-    case 'e':
-      /* Output an extra "e" to make fcmpe, fune.  */
-      if (TARGET_FCMP_EPSILON)
-       fprintf (stream, "e");
-      return;
+         mmix_emit_sp_add (-stack_chunk);
 
-    case 'm':
-      /* Output the number minus 1.  */
-      if (GET_CODE (x) != CONST_INT)
-       {
-         fatal_insn ("MMIX Internal: Bad value for 'm', not a CONST_INT",
-                     x);
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
        }
-      fprintf (stream, HOST_WIDEST_INT_PRINT_DEC,
-              (HOST_WIDEST_INT) (mmix_intval (x) - 1));
-      return;
-
-    case 'p':
-      /* Store the number of registers we want to save.  This was setup
-        by the prologue.  The actual operand contains the number of
-        registers to pass, but we don't use it currently.  Anyway, we
-        need to output the number of saved registers here.  */
-      if (TARGET_ABI_GNU)
-       fprintf (stream, "%d", mmix_highest_saved_stack_register + 1);
-      else
-       /* FIXME: Get the effect of renaming $16, $17.. to the first
-          unused call-saved reg.  */
-       fprintf (stream, "15");
-      return;
 
-    case 'r':
-      /* Store the register to output a constant to.  */
-      if (! REG_P (x))
-       fatal_insn ("MMIX Internal: Expected a register, not this", x);
-      mmix_output_destination_register = REGNO (x);
-      return;
+      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;
+    }
 
-    case 'I':
-      /* Output the constant.  Note that we use this for floats as well.  */
-      if (GET_CODE (x) != CONST_INT
-         && (GET_CODE (x) != CONST_DOUBLE
-             || (GET_MODE (x) != VOIDmode && GET_MODE (x) != DFmode
-                 && GET_MODE (x) != SFmode)))
-       fatal_insn ("MMIX Internal: Expected a constant, not this", x);
-      mmix_output_register_setting (stream,
-                                   mmix_output_destination_register,
-                                   mmix_intval (x), 0);
-      return;
+  if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    {
+      rtx tmpreg, retreg;
+      rtx insn;
 
-    case 'U':
-      /* An U for unsigned, if TARGET_ZERO_EXTEND.  Ignore the operand.  */
-      if (TARGET_ZERO_EXTEND)
-       putc ('U', stream);
-      return;
+      /* 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.  */
 
-    case 'v':
-      mmix_output_shifted_value (stream, (HOST_WIDEST_INT) mmix_intval (x));
-      return;
+      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;
 
-    case 'V':
-      mmix_output_shifted_value (stream, (HOST_WIDEST_INT) ~mmix_intval (x));
-      return;
+         mmix_emit_sp_add (-stack_chunk);
 
-    case 'W':
-      if (GET_CODE (x) != CONST_INT)
-       fatal_insn ("MMIX Internal: Expected a CONST_INT, not this", x);
-      fprintf (stream, "#%x", (int) (INTVAL (x) & 0xffff));
-      return;
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
 
-    case 0:
-      /* Nothing to do.  */
-      break;
+      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));
 
-    default:
-      /* Presumably there's a missing case above if we get here.  */
-      internal_error ("MMIX Internal: Missing `%c' case in mmix_print_operand", code);
+      offset -= 8;
     }
+  else if (MMIX_CFUN_HAS_LANDING_PAD)
+    offset -= 8;
 
-  switch (GET_CODE (modified_x))
+  if (MMIX_CFUN_HAS_LANDING_PAD)
     {
-    case REG:
-      if (REGNO (modified_x) >= FIRST_PSEUDO_REGISTER)
-       internal_error ("MMIX Internal: Bad register: %d", REGNO (modified_x));
-      fprintf (stream, "%s", reg_names[REGNO (modified_x)]);
-      return;
-
-    case MEM:
-      output_address (XEXP (modified_x, 0));
-      return;
-
-    case CONST_INT:
-      /* For -2147483648, mmixal complains that the constant does not fit
-        in 4 bytes, so let's output it as hex.  Take care to handle hosts
-        where HOST_WIDE_INT is longer than an int.
-
-        Print small constants +-255 using decimal.  */
-
-      if (INTVAL (modified_x) > -256 && INTVAL (modified_x) < 256)
-       fprintf (stream, "%d", (int) (INTVAL (modified_x)));
-      else
-       fprintf (stream, "#%x",
-                (int) (INTVAL (modified_x)) & (unsigned int) ~0);
-      return;
+      /* Store the register defining the numbering of local registers, so
+        we know how long to unwind the register stack.  */
 
-    case CONST_DOUBLE:
-      /* Do somewhat as CONST_INT.  */
-      mmix_output_octa (stream, mmix_intval (modified_x), 0);
-      return;
+      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;
 
-    case CONST:
-      output_addr_const (stream, modified_x);
-      return;
+         mmix_emit_sp_add (-stack_chunk);
 
-    default:
-      /* No need to test for all strange things.  Let output_addr_const do
-        it for us.  */
-      if (CONSTANT_P (modified_x)
-         /* Strangely enough, this is not included in CONSTANT_P.
-            FIXME: Ask/check about sanity here.  */
-         || GET_CODE (modified_x) == CODE_LABEL)
-       {
-         output_addr_const (stream, modified_x);
-         return;
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
        }
 
-      /* We need the original here.  */
-      fatal_insn ("MMIX Internal: Cannot decode this operand", x);
-    }
-}
-
-/* PRINT_OPERAND_PUNCT_VALID_P.  */
+      /* 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.  */
 
-int
-mmix_print_operand_punct_valid_p (code)
-     int code ATTRIBUTE_UNUSED;
-{
-  /* A '+' is used for branch prediction, similar to other ports.  */
-  return code == '+';
-}
+      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;
+    }
 
-/* PRINT_OPERAND_ADDRESS.  */
+  /* 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;
 
-void
-mmix_print_operand_address (stream, x)
-     FILE *stream;
-     rtx x;
-{
-  if (REG_P (x))
-    {
-      /* I find the generated assembly code harder to read without
-        the ",0".  */
-      fprintf (stream, "%s,0",reg_names[REGNO (x)]);
-      return;
-    }
-  else if (GET_CODE (x) == PLUS)
-    {
-      rtx x1 = XEXP (x, 0);
-      rtx x2 = XEXP (x, 1);
+  /* Now store all registers that are global, i.e. not saved by the
+     register file machinery.
 
-      /* Try swap the order.  FIXME: Do we need this?  */
-      if (! REG_P (x1))
-       {
-         rtx tem = x1;
-         x1 = x2;
-         x2 = tem;
-       }
+     It is assumed that the frame-pointer is one of these registers, so it
+     is explicitly excluded in the count.  */
 
-      if (REG_P (x1))
-       {
-         fprintf (stream, "%s,", reg_names[REGNO (x1)]);
+  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 (REG_P (x2))
-           {
-             fprintf (stream, "%s", reg_names[REGNO (x2)]);
-             return;
-           }
-         else if (GET_CODE (x2) == CONST_INT
-                  && CONST_OK_FOR_LETTER_P (INTVAL (x2), 'I'))
-           {
-             output_addr_const (stream, x2);
-             return;
-           }
-       }
-    }
+       if (offset < 0)
+         {
+           HOST_WIDE_INT stack_chunk
+             = (stack_space_to_allocate > (256 - offset - 8)
+                ? (256 - offset - 8) : stack_space_to_allocate);
 
-  fatal_insn ("MMIX Internal: This is not a recognized address", x);
-}
+           mmix_emit_sp_add (-stack_chunk);
+           offset += stack_chunk;
+           stack_space_to_allocate -= stack_chunk;
+         }
 
-/* ASM_OUTPUT_REG_PUSH.  */
+       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;
+      }
 
-void
-mmix_asm_output_reg_push (stream, regno)
-     FILE * stream;
-     int regno;
-{
-  fprintf (stream, "\tSUBU %s,%s,8\n\tSTOU %s,%s,0\n",
-          reg_names[MMIX_STACK_POINTER_REGNUM],
-          reg_names[MMIX_STACK_POINTER_REGNUM],
-          reg_names[regno],
-          reg_names[MMIX_STACK_POINTER_REGNUM]);
+  /* 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);
 }
 
-/* ASM_OUTPUT_REG_POP.  */
+/* Expands the function epilogue into RTX.  */
 
 void
-mmix_asm_output_reg_pop (stream, regno)
-     FILE * stream;
-     int regno;
+mmix_expand_epilogue (void)
 {
-  fprintf (stream, "\tLDOU %s,%s,0\n\tINCL %s,8\n",
-          reg_names[regno],
-          reg_names[MMIX_STACK_POINTER_REGNUM],
-          reg_names[MMIX_STACK_POINTER_REGNUM]);
-}
+  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;
 
-/* ASM_OUTPUT_ADDR_DIFF_ELT.  */
+  /* The first address to access is beyond the outgoing_args area.  */
+  HOST_WIDE_INT offset = current_function_outgoing_args_size;
 
-void
-mmix_asm_output_addr_diff_elt (stream, body, value, rel)
-     FILE *stream;
-     rtx body ATTRIBUTE_UNUSED;
-     int value;
-     int rel;
-{
-  fprintf (stream, "\tTETRA L%d-L%d\n", value, rel);
-}
+  /* 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;
 
-/* ASM_OUTPUT_ADDR_VEC_ELT.  */
+  /* 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;
 
-void
-mmix_asm_output_addr_vec_elt (stream, value)
-     FILE *stream;
-     int value;
-{
-  fprintf (stream, "\tOCTA L:%d\n", value);
-}
+  /* Add in the frame-pointer.  */
+  if (frame_pointer_needed)
+    stack_space_to_deallocate += 8;
 
-/* ASM_OUTPUT_SKIP.  */
+  /* 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);
 
-void
-mmix_asm_output_skip (stream, nbytes)
-     FILE *stream;
-     int nbytes;
-{
-  fprintf (stream, "\tLOC @+%d\n", nbytes);
-}
+  /* 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.  */
 
-/* ASM_OUTPUT_ALIGN.  */
+  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;
+         }
 
-void
-mmix_asm_output_align (stream, power)
-     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
-     .align) so people will never have to wonder about whether the
-     argument is in number of bytes or the log2 thereof.  We do it in
-     addition to the LOC directive, so nothing needs tweaking when
-     copy-pasting assembly into mmixal.  */
- fprintf (stream, "\t.p2align %d\n", power);
- fprintf (stream, "\tLOC @+(%d-@)&%d\n", 1 << power, (1 << power) - 1);
-}
+       emit_move_insn (gen_rtx_REG (DImode, regno),
+                       gen_rtx_MEM (DImode,
+                                    plus_constant (stack_pointer_rtx,
+                                                   offset)));
+       offset += 8;
+      }
 
-/* DBX_REGISTER_NUMBER.  */
+  /* Here is where the local variables were.  As in the prologue, they
+     might be of an unaligned size.  */
+  offset += (locals_size + 7) & ~7;
 
-int
-mmix_dbx_register_number (regno)
-     int regno;
-{
-  /* FIXME: Implement final register renumbering if necessary.  (Use
-     target state in cfun).  */
+  /* 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;
 
-  /* We need to renumber registers to get the number of the return address
-     register in the range 0..255.  It is also space-saving if registers
-     mentioned in the call-frame information (which uses this function by
-     defaulting DWARF_FRAME_REGNUM to DBX_REGISTER_NUMBER) are numbered
-     0 .. 63.  So map 224 .. 256+15 -> 0 .. 47 and 0 .. 223 -> 48..223+48.  */
-  return regno >= 224 ? (regno - 224) : (regno + 48);
-}
+  /* Get back the old frame-pointer-value.  */
+  if (frame_pointer_needed)
+    {
+      if (offset > 255)
+       {
+         mmix_emit_sp_add (offset);
 
-/* End of target macro support functions.
+         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;
+    }
 
-   Now MMIX's own functions.  First the exported ones.  */
+  /* 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
@@ -2516,11 +2228,10 @@ mmix_dbx_register_number (regno)
    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");
@@ -2571,25 +2282,52 @@ mmix_output_register_setting (stream, regno, value, do_begin_end)
       static const char *const higher_parts[] = {"L", "ML", "MH", "H"};
       const char *op = "SET";
       const char *line_begin = "";
+      int insns = 0;
       int i;
+      HOST_WIDEST_INT tmpvalue = value;
 
-      /* Output pertinent parts of the 4-wyde sequence.
-        Still more to do if we want this to be optimal, but hey...
-        Note that the zero case has been handled above.  */
-      for (i = 0; i < 4 && value != 0; i++)
+      /* Compute the number of insns needed to output this constant.  */
+      for (i = 0; i < 4 && tmpvalue != 0; i++)
+       {
+         if (tmpvalue & 65535)
+           insns++;
+         tmpvalue >>= 16;
+       }
+      if (TARGET_BASE_ADDRESSES && insns == 3)
+       {
+         /* The number three is based on a static observation on
+            ghostscript-6.52.  Two and four are excluded because there
+            are too many such constants, and each unique constant (maybe
+            offset by 1..255) were used few times compared to other uses,
+            e.g. addresses.
+
+            We use base-plus-offset addressing to force it into a global
+            register; we just use a "LDA reg,VALUE", which will cause the
+            assembler and linker to DTRT (for constants as well as
+            addresses).  */
+         fprintf (stream, "LDA %s,", reg_names[regno]);
+         mmix_output_octa (stream, value, 0);
+       }
+      else
        {
-         if (value & 65535)
+         /* Output pertinent parts of the 4-wyde sequence.
+            Still more to do if we want this to be optimal, but hey...
+            Note that the zero case has been handled above.  */
+         for (i = 0; i < 4 && value != 0; i++)
            {
-             fprintf (stream, "%s%s%s %s,#%x", line_begin, op,
-                      higher_parts[i], reg_names[regno],
-                      (int) (value & 65535));
-             /* The first one sets the rest of the bits to 0, the next
-                ones add set bits.  */
-             op = "INC";
-             line_begin = "\n\t";
-           }
+             if (value & 65535)
+               {
+                 fprintf (stream, "%s%s%s %s,#%x", line_begin, op,
+                          higher_parts[i], reg_names[regno],
+                          (int) (value & 65535));
+                 /* The first one sets the rest of the bits to 0, the next
+                    ones add set bits.  */
+                 op = "INC";
+                 line_begin = "\n\t";
+               }
 
-         value >>= 16;
+             value >>= 16;
+           }
        }
     }
 
@@ -2601,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.  */
@@ -2625,176 +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'));
-}
-
-/* True if this is a register or an int 0..256.  We include 256,
-   because it can be canonicalized into 255 for comparisons, which is
-   currently the only use of this predicate.
-   FIXME:  Check that this happens and does TRT.  */
-
-int
-mmix_reg_or_8bit_or_256_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return mmix_reg_or_8bit_operand (op, mode)
-    || (GET_CODE (op) == CONST_INT && INTVAL (op) == 256);
-}
-
 /* 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);
@@ -2823,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;
@@ -2845,8 +2416,6 @@ mmix_gen_compare_reg (code, x, y)
   if (! REG_P (x) && ! REG_P (y))
     x = force_reg (mode, x);
 
-  CANONICALIZE_COMPARISON (code, x, y);
-
   /* If it's not quite right yet, put y in a register.  */
   if (! REG_P (y)
       && (GET_CODE (y) != CONST_INT
@@ -2861,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;
@@ -2899,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
@@ -2936,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;
 
@@ -2950,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;
   }
@@ -2974,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
   {
@@ -2994,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"},
@@ -3047,17 +2648,17 @@ mmix_output_condition (stream, x, reversed)
        {CCmode, cc_signed_convs},
        {DImode, cc_di_convs}};
 
-  unsigned int i;
+  size_t i;
   int j;
 
   enum machine_mode mode = GET_MODE (XEXP (x, 0));
   RTX_CODE cc = GET_CODE (x);
 
-  for (i = 0; i < sizeof (cc_convs)/sizeof(*cc_convs); i++)
+  for (i = 0; i < ARRAY_SIZE (cc_convs); i++)
     {
       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
@@ -3082,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;
 
@@ -3124,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)
        {
@@ -3150,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")