OSDN Git Service

Emit MMIX function prologue and epilogue as rtl.
authorhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 7 Jul 2002 17:13:14 +0000 (17:13 +0000)
committerhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 7 Jul 2002 17:13:14 +0000 (17:13 +0000)
* config/mmix/mmix.md ("call"): Use mmix_get_hard_reg_initial_val,
not unprototyped get_hard_reg_initial_val.
("call_value", "nonlocal_goto_receiver"): Ditto.
("return"): Make define_expand.  Move real insn to...
("*expanded_return"): New pattern.
("prologue", "epilogue"): New define_expands.
* config/mmix/mmix.h (MMIX_rO_REGNUM): New macro.
(struct machine_function): New member in_prologue.
(FIRST_PSEUDO_REGISTER): Adjust for including rO as register.
(FIXED_REGISTERS, CALL_USED_REGISTERS): Ditto.
(MMIX_MMIXWARE_ABI_REG_ALLOC_ORDER): Ditto.
(MMIX_GNU_ABI_REG_ALLOC_ORDER, REG_CLASS_CONTENTS): Ditto.
(REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): Ditto.
(LOCAL_REGNO): Define.  Adjust comment.
* config/mmix/mmix.c (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS):
Consider regs_ever_live[MMIX_rJ_REGNUM], not just
leaf_function_p.
(MMIX_OUTPUT_REGNO): Don't translate registers while outputting
the prologue.
(mmix_target_asm_function_prologue): Make static.  Just mark that
the prologue is being emitted.  Move guts to...
(mmix_expand_prologue): New function.  Adjust for emitting
prologue as rtl.  For sizes, use HOST_WIDE_INT only.
(mmix_target_asm_function_epilogue): Make static.  Simply emit a
\n.  Move guts to...
(mmix_expand_epilogue): New function.  Adjust for emitting
epilogue as rtl.  For sizes, use HOST_WIDE_INT only.
(mmix_target_asm_function_end_prologue): Mark that the prologue
has ended.
(TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
(mmix_conditional_register_usage): Improve comments.
(mmix_local_regno): New function.
(mmix_emit_sp_add, mmix_get_hard_reg_initial_val): Ditto.
* config/mmix/mmix-protos.h (mmix_local_regno): Prototype.
(mmix_expand_prologue, mmix_expand_epilogue): Ditto.
(mmix_get_hard_reg_initial_val): Ditto.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@55302 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mmix/mmix-protos.h
gcc/config/mmix/mmix.c
gcc/config/mmix/mmix.h
gcc/config/mmix/mmix.md

index 4367e69..2a1b683 100644 (file)
@@ -1,3 +1,43 @@
+2002-07-07  Hans-Peter Nilsson  <hp@bitrange.com>
+
+       Emit MMIX function prologue and epilogue as rtl.
+       * config/mmix/mmix.md ("call"): Use mmix_get_hard_reg_initial_val,
+       not unprototyped get_hard_reg_initial_val.
+       ("call_value", "nonlocal_goto_receiver"): Ditto.
+       ("return"): Make define_expand.  Move real insn to...
+       ("*expanded_return"): New pattern.
+       ("prologue", "epilogue"): New define_expands.
+       * config/mmix/mmix.h (MMIX_rO_REGNUM): New macro.
+       (struct machine_function): New member in_prologue.
+       (FIRST_PSEUDO_REGISTER): Adjust for including rO as register.
+       (FIXED_REGISTERS, CALL_USED_REGISTERS): Ditto.
+       (MMIX_MMIXWARE_ABI_REG_ALLOC_ORDER): Ditto.
+       (MMIX_GNU_ABI_REG_ALLOC_ORDER, REG_CLASS_CONTENTS): Ditto.
+       (REGISTER_NAMES, ADDITIONAL_REGISTER_NAMES): Ditto.
+       (LOCAL_REGNO): Define.  Adjust comment.
+       * config/mmix/mmix.c (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS):
+       Consider regs_ever_live[MMIX_rJ_REGNUM], not just
+       leaf_function_p.
+       (MMIX_OUTPUT_REGNO): Don't translate registers while outputting
+       the prologue.
+       (mmix_target_asm_function_prologue): Make static.  Just mark that
+       the prologue is being emitted.  Move guts to...
+       (mmix_expand_prologue): New function.  Adjust for emitting
+       prologue as rtl.  For sizes, use HOST_WIDE_INT only.
+       (mmix_target_asm_function_epilogue): Make static.  Simply emit a
+       \n.  Move guts to...
+       (mmix_expand_epilogue): New function.  Adjust for emitting
+       epilogue as rtl.  For sizes, use HOST_WIDE_INT only.
+       (mmix_target_asm_function_end_prologue): Mark that the prologue
+       has ended.
+       (TARGET_ASM_FUNCTION_END_PROLOGUE): Define.
+       (mmix_conditional_register_usage): Improve comments.
+       (mmix_local_regno): New function.
+       (mmix_emit_sp_add, mmix_get_hard_reg_initial_val): Ditto.
+       * config/mmix/mmix-protos.h (mmix_local_regno): Prototype.
+       (mmix_expand_prologue, mmix_expand_epilogue): Ditto.
+       (mmix_get_hard_reg_initial_val): Ditto.
+
 2002-07-06  Andreas Jaeger  <aj@suse.de>
 
        * toplev.c (set_fast_math_flags): Don't use ISO C style function
index 5cfe561..f13a179 100644 (file)
@@ -57,6 +57,7 @@ extern int mmix_shiftable_wyde_value PARAMS ((unsigned HOST_WIDEST_INT));
 extern void mmix_output_register_setting
   PARAMS ((FILE *, int, HOST_WIDEST_INT, int));
 extern void mmix_conditional_register_usage PARAMS ((void));
+extern int mmix_local_regno PARAMS ((int));
 extern int mmix_dbx_register_number PARAMS ((int));
 
 /* Things that need rtl.h, tree.h or real.h included, or in combination.  */
@@ -123,6 +124,9 @@ extern void mmix_print_operand_address PARAMS ((FILE *, rtx));
 extern int mmix_valid_comparison PARAMS ((RTX_CODE, enum machine_mode, rtx));
 extern rtx mmix_gen_compare_reg PARAMS ((enum rtx_code, rtx, rtx));
 extern void mmix_machine_dependent_reorg PARAMS ((rtx));
+extern void mmix_expand_prologue PARAMS ((void));
+extern void mmix_expand_epilogue PARAMS ((void));
+extern rtx mmix_get_hard_reg_initial_val PARAMS ((enum machine_mode, int));
 #endif /* RTX_CODE */
 
 extern int mmix_asm_preferred_eh_data_format PARAMS ((int, int));
index 7dbfb2e..c3c4d98 100644 (file)
@@ -52,9 +52,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, regs_ever_live[] 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
+   preferrable.  */
+#define MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS                        \
+ (flag_exceptions                                              \
+  && ((reload_completed && regs_ever_live[MMIX_rJ_REGNUM])     \
+      || !leaf_function_p ()))
 
 #define IS_MMIX_EH_RETURN_DATA_REG(REGNO)      \
  (current_function_calls_eh_return             \
@@ -68,11 +78,15 @@ Boston, MA 02111-1307, USA.  */
    registers.  In effect this makes unused call-saved registers to be used
    as call-clobbered registers.  The benefit comes from keeping the number
    of local registers (value of rL) low, since there's a cost of
-   increasing rL and clearing unused (unset) registers with lower numbers.  */
+   increasing rL and clearing unused (unset) registers with lower numbers.
+   Don't translate while outputting the prologue.  */
 #define MMIX_OUTPUT_REGNO(N)                                   \
  (TARGET_ABI_GNU                                               \
   || (int) (N) < MMIX_RETURN_VALUE_REGNUM                      \
   || (int) (N) > MMIX_LAST_STACK_REGISTER_REGNUM               \
+  || cfun == NULL                                              \
+  || cfun->machine == NULL                                     \
+  || cfun->machine->in_prologue                                        \
   ? (N) : ((N) - MMIX_RETURN_VALUE_REGNUM                      \
           + cfun->machine->highest_saved_stack_register + 1))
 
@@ -110,10 +124,11 @@ static bool mmix_assemble_integer PARAMS ((rtx, unsigned int, int));
 static struct machine_function * mmix_init_machine_status PARAMS ((void));
 static void mmix_encode_section_info PARAMS ((tree, int));
 static const char *mmix_strip_name_encoding PARAMS ((const char *));
-
-extern void mmix_target_asm_function_prologue
+static void mmix_emit_sp_add PARAMS ((HOST_WIDE_INT offset));
+static void mmix_target_asm_function_prologue
   PARAMS ((FILE *, HOST_WIDE_INT));
-extern void mmix_target_asm_function_epilogue
+static void mmix_target_asm_function_end_prologue PARAMS ((FILE *));
+static void mmix_target_asm_function_epilogue
   PARAMS ((FILE *, HOST_WIDE_INT));
 
 
@@ -136,6 +151,9 @@ extern void mmix_target_asm_function_epilogue
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE mmix_target_asm_function_prologue
 
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE mmix_target_asm_function_end_prologue
+
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE mmix_target_asm_function_epilogue
 
@@ -241,11 +259,11 @@ mmix_conditional_register_usage ()
 
       /* Change the default from the mmixware ABI.  For the GNU ABI,
         $15..$30 are call-saved just as $0..$14.  There must be one
-        call-clobbered local register for the "hole" describing number of
-        saved local registers saved by PUSHJ/PUSHGO during the function
-        call, receiving the return value at return.  So best is to use
-        the highest, $31.  It's already marked call-clobbered for the
-        mmixware ABI.  */
+        call-clobbered local register for the "hole" that holds the
+        number of saved local registers saved by PUSHJ/PUSHGO during the
+        function call, receiving the return value at return.  So best is
+        to use the highest, $31.  It's already marked call-clobbered for
+        the mmixware ABI.  */
       for (i = 15; i <= 30; i++)
        call_used_regs[i] = 0;
 
@@ -263,6 +281,17 @@ mmix_conditional_register_usage ()
        reg_names[i]++;
 }
 
+/* LOCAL_REGNO.
+   All registers that are part of the register stack and that will be
+   saved are local.  */
+
+int
+mmix_local_regno (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.  */
 
@@ -672,335 +701,25 @@ mmix_asm_preferred_eh_data_format (code, global)
   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 of the prologue.  This
+   matters to whether we'll translate register numbers as calculated by
+   mmix_machine_dependent_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 (stream, framesize)
+     FILE *stream ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT framesize ATTRIBUTE_UNUSED;
 {
-  int regno;
-  int stack_space_to_allocate
-    = (current_function_outgoing_args_size
-       + current_function_pretend_args_size
-       + (int) locals_size + 7) & ~7;
-  int offset = -8;
-  int doing_dwarf = dwarf2out_do_frame ();
-  long cfa_offset = 0;
-
-  /* Guard our assumptions.  Very low priority FIXME.  */
-  if (locals_size != (int) locals_size)
-    error ("stack frame too big");
-
-  /* Add room needed to save global non-register-stack registers.  */
-  for (regno = 255;
-       regno >= MMIX_FIRST_GLOBAL_REGNUM;
-       regno--)
-    /* Note that we assume that the frame-pointer-register is one of these
-       registers, in which case we don't count it here.  */
-    if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-         && regs_ever_live[regno] && !call_used_regs[regno]))
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      stack_space_to_allocate += 8;
-
-  /* If we do have a frame-pointer, add room for it.  */
-  if (frame_pointer_needed)
-    stack_space_to_allocate += 8;
-
-  /* If we have a non-local label, we need to be able to unwind to it, so
-     store the current register stack pointer.  Also store the return
-     address if we do that.  */
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    stack_space_to_allocate += 16;
-  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    /* If we do have a saved return-address slot, add room for it.  */
-    stack_space_to_allocate += 8;
-
-  /* Make sure we don't get an unaligned stack.  */
-  if ((stack_space_to_allocate % 8) != 0)
-    internal_error ("stack frame not a multiple of 8 bytes: %d",
-                   stack_space_to_allocate);
-
-  if (current_function_pretend_args_size)
-    {
-      int mmix_first_vararg_reg
-       = (MMIX_FIRST_INCOMING_ARG_REGNUM
-          + (MMIX_MAX_ARGS_IN_REGS
-             - current_function_pretend_args_size / 8));
-
-      for (regno
-            = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
-          regno >= mmix_first_vararg_reg;
-          regno--)
-       {
-         if (offset < 0)
-           {
-             int stack_chunk
-               = stack_space_to_allocate > (256 - 8)
-               ? (256 - 8) : stack_space_to_allocate;
-
-             fprintf (stream, "\tSUBU %s,%s,%d\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      stack_chunk);
-
-             if (doing_dwarf)
-               {
-                 /* Each call to dwarf2out_def_cfa overrides the previous
-                    setting; they don't accumulate.  We must keep track
-                    of the offset ourselves.  */
-                 cfa_offset += stack_chunk;
-                 if (!frame_pointer_needed)
-                   dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                      cfa_offset);
-               }
-             offset += stack_chunk;
-             stack_space_to_allocate -= stack_chunk;
-           }
-
-         fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  offset);
-
-         /* These registers aren't actually saved (as in "will be
-            restored"), so don't tell DWARF2 they're saved.  */
-
-         offset -= 8;
-       }
-    }
-
-  /* Store the frame-pointer.  */
-
-  if (frame_pointer_needed)
-    {
-      if (offset < 0)
-       {
-         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
-         int stack_chunk
-           = stack_space_to_allocate > (256 - 8 - 8)
-           ? (256 - 8 - 8) : stack_space_to_allocate;
-
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_chunk);
-         if (doing_dwarf)
-           cfa_offset += stack_chunk;
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-       }
-
-      fprintf (stream, "\tSTOU %s,%s,%d\n\tADDU %s,%s,%d\n",
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset,
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset + 8);
-      if (doing_dwarf)
-       {
-         /* If we're using the frame-pointer, then we just need this CFA
-            definition basing on that value (often equal to the CFA).
-            Further changes to the stack-pointer do not affect the
-            frame-pointer, so we conditionalize them below on
-            !frame_pointer_needed.  */
-         dwarf2out_def_cfa ("", MMIX_FRAME_POINTER_REGNUM,
-                            -cfa_offset + offset + 8);
-
-         dwarf2out_reg_save ("", MMIX_FRAME_POINTER_REGNUM,
-                             -cfa_offset + offset);
-       }
-
-      offset -= 8;
-    }
-
-  if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    {
-      /* Store the return-address, if one is needed on the stack.  We
-        usually store it in a register when needed, but that doesn't work
-        with -fexceptions.  */
-
-      if (offset < 0)
-       {
-         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
-         int stack_chunk
-           = stack_space_to_allocate > (256 - 8 - 8)
-           ? (256 - 8 - 8) : stack_space_to_allocate;
-
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_chunk);
-         if (doing_dwarf)
-           {
-             cfa_offset += stack_chunk;
-             if (!frame_pointer_needed)
-               dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                  cfa_offset);
-           }
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-       }
-
-      fprintf (stream, "\tGET $255,rJ\n\tSTOU $255,%s,%d\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset);
-      if (doing_dwarf)
-       dwarf2out_return_save ("", -cfa_offset + offset);
-      offset -= 8;
-    }
-  else if (MMIX_CFUN_HAS_LANDING_PAD)
-    offset -= 8;
-
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    {
-      /* Store the register defining the numbering of local registers, so
-        we know how long to unwind the register stack.  */
-
-      if (offset < 0)
-       {
-         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
-         int stack_chunk
-           = stack_space_to_allocate > (256 - 8 - 8)
-           ? (256 - 8 - 8) : stack_space_to_allocate;
-
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_chunk);
-         offset += stack_chunk;
-         stack_space_to_allocate -= stack_chunk;
-
-         if (doing_dwarf)
-           {
-             cfa_offset += stack_chunk;
-             if (!frame_pointer_needed)
-               dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                cfa_offset);
-           }
-       }
-
-      /* We don't tell dwarf2 about this one; we just have it to unwind
-        the register stack at landing pads.  FIXME: It's a kludge because
-        we can't describe the effect of the PUSHJ and PUSHGO insns on the
-        register stack at the moment.  Best thing would be to handle it
-        like stack-pointer offsets.  Better: some hook into dwarf2out.c
-        to produce DW_CFA_expression:s that specify the increment of rO,
-        and unwind it at eh_return (preferred) or at the landing pad.
-        Then saves to $0..$G-1 could be specified through that register.  */
-
-      fprintf (stream, "\tGET $255,rO\n\tSTOU $255,%s,%d\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-
-      offset -= 8;
-    }
-
-  /* After the return-address and the frame-pointer, we have the local
-     variables.  They're the ones that may have an "unaligned" size.  */
-  offset -= (locals_size + 7) & ~7;
-
-  /* Now store all registers that are global, i.e. not saved by the
-     register file machinery.
-
-     It is assumed that the frame-pointer is one of these registers, so it
-     is explicitly excluded in the count.  */
-
-  for (regno = 255;
-       regno >= MMIX_FIRST_GLOBAL_REGNUM;
-       regno--)
-    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-        && regs_ever_live[regno] && ! call_used_regs[regno])
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      {
-       if (offset < 0)
-         {
-           int stack_chunk;
-
-           /* Since the local variables go above, we may get a large
-              offset here.  */
-           if (offset < -248)
-             {
-               /* We're not going to access the locals area in the
-                  prologue, so we'll just silently subtract the slab we
-                  will not access.  */
-               stack_chunk =
-                 stack_space_to_allocate > (256 - offset - 8)
-                 ? (256 - offset - 8) : stack_space_to_allocate;
-
-               mmix_output_register_setting (stream, 255, stack_chunk, 1);
-               fprintf (stream, "\tSUBU %s,%s,$255\n",
-                        reg_names[MMIX_STACK_POINTER_REGNUM],
-                        reg_names[MMIX_STACK_POINTER_REGNUM]);
-
-               if (doing_dwarf)
-                 {
-                   cfa_offset += stack_chunk;
-                   if (!frame_pointer_needed)
-                     dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                        cfa_offset);
-                 }
-             }
-           else
-             {
-               stack_chunk = stack_space_to_allocate > (256 - 8)
-                 ? (256 - 8) : stack_space_to_allocate;
-
-               fprintf (stream, "\tSUBU %s,%s,%d\n",
-                        reg_names[MMIX_STACK_POINTER_REGNUM],
-                        reg_names[MMIX_STACK_POINTER_REGNUM], stack_chunk);
-               if (doing_dwarf)
-                 {
-                   cfa_offset += stack_chunk;
-                   if (!frame_pointer_needed)
-                     dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                                        cfa_offset);
-                 }
-             }
-
-           offset += stack_chunk;
-           stack_space_to_allocate -= stack_chunk;
-         }
-
-       fprintf (stream, "\tSTOU %s,%s,%d\n", reg_names[regno],
-              reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-       if (doing_dwarf)
-         dwarf2out_reg_save ("", regno, -cfa_offset + offset);
-       offset -= 8;
-      }
+  cfun->machine->in_prologue = 1;
+}
 
-  /* Finally, allocate room for outgoing args and local vars if room
-     wasn't allocated above.  This might be any number of bytes (well, we
-     assume it fits in a host-int).  */
-  if (stack_space_to_allocate)
-    {
-      if (stack_space_to_allocate < 256)
-       {
-         fprintf (stream, "\tSUBU %s,%s,%d\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  stack_space_to_allocate);
-       }
-      else
-       {
-         mmix_output_register_setting (stream, 255,
-                                       stack_space_to_allocate, 1);
-         fprintf (stream, "\tSUBU %s,%s,$255\n",
-                  reg_names[MMIX_STACK_POINTER_REGNUM],
-                  reg_names[MMIX_STACK_POINTER_REGNUM]);
-       }
+/* Make a note that we've seen the end of the prologue.  */
 
-      if (doing_dwarf)
-       {
-         cfa_offset += stack_space_to_allocate;
-         if (!frame_pointer_needed)
-           dwarf2out_def_cfa ("", MMIX_STACK_POINTER_REGNUM,
-                              cfa_offset);
-       }
-    }
+static void
+mmix_target_asm_function_end_prologue (stream)
+     FILE *stream ATTRIBUTE_UNUSED;
+{
+  cfun->machine->in_prologue = 0;
 }
 
 /* MACHINE_DEPENDENT_REORG.
@@ -1055,210 +774,40 @@ mmix_target_asm_function_epilogue (stream, locals_size)
      HOST_WIDE_INT locals_size;
 
 {
-  int regno;
-  int stack_space_to_deallocate
-    = (current_function_outgoing_args_size
-       + current_function_pretend_args_size
-       + (int) locals_size + 7) & ~7;
+  /* Emit an \n for readability of the generated assembly.  */
+  fputc ('\n', stream);
+}
 
-  /* The assumption that locals_size fits in an int is asserted in
-     mmix_target_asm_function_prologue.  */
+/* ASM_OUTPUT_MI_THUNK.  */
 
-  /* The first address to access is beyond the outgoing_args area.  */
-  int offset = current_function_outgoing_args_size;
+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];
 
-  rtx insn = get_last_insn ();
-
-  /* If the last insn was a BARRIER, we don't have to write any code,
-     then all returns were covered by "return" insns.  */
-  if (GET_CODE (insn) == NOTE)
-    insn = prev_nonnote_insn (insn);
-  if (insn
-      && (GET_CODE (insn) == BARRIER
-         /* We must make sure that the insn really is a "return" and
-            not a conditional branch.  Try to match the return exactly,
-            and if it doesn't match, assume it is a conditional branch
-            (and output an epilogue).  */
-         || (GET_CODE (insn) == JUMP_INSN
-             && GET_CODE (PATTERN (insn)) == RETURN)))
+  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
     {
-      /* Emit an extra \n as is done with the normal epilogue.  */
-      fputc ('\n', stream);
-      return;
+      mmix_output_register_setting (stream, 255, delta, 1);
+      asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
     }
 
-  /* Add the space for global non-register-stack registers.
-     It is assumed that the frame-pointer register can be one of these
-     registers, in which case it is excluded from the count when needed.  */
-  for (regno = 255;
-       regno >= MMIX_FIRST_GLOBAL_REGNUM;
-       regno--)
-    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-        && regs_ever_live[regno] && !call_used_regs[regno])
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      stack_space_to_deallocate += 8;
-
-  /* Add in the space for register stack-pointer.  If so, always add room
-     for the saved PC.  */
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    stack_space_to_deallocate += 16;
-  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    /* If we have a saved return-address slot, add it in.  */
-    stack_space_to_deallocate += 8;
+  fprintf (stream, "\tJMP ");
+  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
+  fprintf (stream, "\n");
+}
 
-  /* Add in the frame-pointer.  */
-  if (frame_pointer_needed)
-    stack_space_to_deallocate += 8;
-
-  /* Make sure we don't get an unaligned stack.  */
-  if ((stack_space_to_deallocate % 8) != 0)
-    internal_error ("stack frame not a multiple of octabyte: %d",
-                   stack_space_to_deallocate);
-
-  /* We will add back small offsets to the stack pointer as we go.
-     First, we restore all registers that are global, i.e. not saved by
-     the register file machinery.  */
-
-  for (regno = MMIX_FIRST_GLOBAL_REGNUM;
-       regno <= 255;
-       regno++)
-    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
-        && regs_ever_live[regno] && !call_used_regs[regno])
-       || IS_MMIX_EH_RETURN_DATA_REG (regno))
-      {
-       if (offset > 255)
-         {
-           if (offset > 65535)
-             {
-               /* There's better support for incrementing than
-                  decrementing, so we might be able to optimize this as
-                  we see a need.  */
-               mmix_output_register_setting (stream, 255, offset, 1);
-               fprintf (stream, "\tADDU %s,%s,$255\n",
-                        reg_names[MMIX_STACK_POINTER_REGNUM],
-                        reg_names[MMIX_STACK_POINTER_REGNUM]);
-             }
-           else
-             fprintf (stream, "\tINCL %s,%d\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-
-           stack_space_to_deallocate -= offset;
-           offset = 0;
-         }
-
-       fprintf (stream, "\tLDOU %s,%s,%d\n",
-                reg_names[regno],
-                reg_names[MMIX_STACK_POINTER_REGNUM],
-                offset);
-       offset += 8;
-      }
-
-  /* Here is where the local variables were.  As in the prologue, they
-     might be of an unaligned size.  */
-  offset += (locals_size + 7) & ~7;
-
-
-  /* The saved register stack pointer is just below the frame-pointer
-     register.  We don't need to restore it "manually"; the POP
-     instruction does that.  */
-  if (MMIX_CFUN_HAS_LANDING_PAD)
-    offset += 16;
-  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
-    /* The return-address slot is just below the frame-pointer register.
-       We don't need to restore it because we don't really use it.  */
-    offset += 8;
-
-  /* Get back the old frame-pointer-value.  */
-  if (frame_pointer_needed)
-    {
-      if (offset > 255)
-       {
-         if (offset > 65535)
-           {
-             /* There's better support for incrementing than
-                decrementing, so we might be able to optimize this as
-                we see a need.  */
-             mmix_output_register_setting (stream, 255, offset, 1);
-             fprintf (stream, "\tADDU %s,%s,$255\n",
-                      reg_names[MMIX_STACK_POINTER_REGNUM],
-                      reg_names[MMIX_STACK_POINTER_REGNUM]);
-           }
-         else
-           fprintf (stream, "\tINCL %s,%d\n",
-                    reg_names[MMIX_STACK_POINTER_REGNUM], offset);
-
-         stack_space_to_deallocate -= offset;
-         offset = 0;
-       }
-
-      fprintf (stream, "\tLDOU %s,%s,%d\n",
-              reg_names[MMIX_FRAME_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              offset);
-      offset += 8;
-    }
-
-  /* We do not need to restore pretended incoming args, just add back
-     offset to sp.  */
-  if (stack_space_to_deallocate > 65535)
-    {
-      /* There's better support for incrementing than decrementing, so
-        we might be able to optimize this as we see a need.  */
-      mmix_output_register_setting (stream, 255,
-                                   stack_space_to_deallocate, 1);
-      fprintf (stream, "\tADDU %s,%s,$255\n",
-              reg_names[MMIX_STACK_POINTER_REGNUM],
-              reg_names[MMIX_STACK_POINTER_REGNUM]);
-    }
-  else if (stack_space_to_deallocate != 0)
-    fprintf (stream, "\tINCL %s,%d\n",
-            reg_names[MMIX_STACK_POINTER_REGNUM],
-            stack_space_to_deallocate);
-
-  if (current_function_calls_eh_return)
-    /* Adjustment the (normal) stack-pointer to that of the receiver.
-       FIXME: It would be nice if we could also adjust the register stack
-       here, but we need to express it through DWARF 2 too.  */
-    fprintf (stream, "\tADDU %s,%s,%s\n",
-            reg_names [MMIX_STACK_POINTER_REGNUM],
-            reg_names [MMIX_STACK_POINTER_REGNUM],
-            reg_names [MMIX_EH_RETURN_STACKADJ_REGNUM]);
-
-  /* The extra \n is so we have a blank line between the assembly code of
-     separate functions.  */
-  fprintf (stream, "\tPOP %d,0\n\n", MMIX_POP_ARGUMENT ());
-}
-
-/* ASM_OUTPUT_MI_THUNK.  */
-
-void
-mmix_asm_output_mi_thunk (stream, fndecl, delta, func)
-     FILE * stream;
-     tree fndecl ATTRIBUTE_UNUSED;
-     int delta;
-     tree func;
-{
-  /* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
-     (i.e. pass location of structure to return as invisible first
-     argument) you need to tweak this code too.  */
-  const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
-
-  if (delta >= 0 && delta < 65536)
-    asm_fprintf (stream, "\tINCL %s,%d\n", delta, regname);
-  else if (delta < 0 && delta >= -255)
-    asm_fprintf (stream, "\tSUBU %s,%s,%d\n", regname, regname, -delta);
-  else
-    {
-      mmix_output_register_setting (stream, 255, delta, 1);
-      asm_fprintf (stream, "\tADDU %s,%s,$255\n", regname, regname);
-    }
-
-  fprintf (stream, "\tJMP ");
-  assemble_name (stream, XSTR (XEXP (DECL_RTL (func), 0), 0));
-  fprintf (stream, "\n");
-}
-
-/* FUNCTION_PROFILER.  */
+/* FUNCTION_PROFILER.  */
 
 void
 mmix_function_profiler (stream, labelno)
@@ -2483,8 +2032,19 @@ mmix_dbx_register_number (regno)
 
    Now MMIX'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 (mode, regno)
+     enum machine_mode mode;
+     int regno;
+{
+  return get_hard_reg_initial_val (mode, regno);
+}
+
 /* Non-zero when the function epilogue is simple enough that a single
-   "POP %d,0" should be used.  */
+   "POP %d,0" should be used even within the function.  */
 
 int
 mmix_use_simple_return ()
@@ -2520,6 +2080,360 @@ mmix_use_simple_return ()
   return stack_space_to_allocate == 0;
 }
 
+
+/* Expands the function prologue into RTX.  */
+
+void
+mmix_expand_prologue ()
+{
+  HOST_WIDE_INT locals_size = get_frame_size ();
+  int regno;
+  HOST_WIDE_INT stack_space_to_allocate
+    = (current_function_outgoing_args_size
+       + current_function_pretend_args_size
+       + locals_size + 7) & ~7;
+  HOST_WIDE_INT offset = -8;
+
+  /* Add room needed to save global non-register-stack registers.  */
+  for (regno = 255;
+       regno >= MMIX_FIRST_GLOBAL_REGNUM;
+       regno--)
+    /* Note that we assume that the frame-pointer-register is one of these
+       registers, in which case we don't count it here.  */
+    if ((((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+         && regs_ever_live[regno] && !call_used_regs[regno]))
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      stack_space_to_allocate += 8;
+
+  /* If we do have a frame-pointer, add room for it.  */
+  if (frame_pointer_needed)
+    stack_space_to_allocate += 8;
+
+  /* If we have a non-local label, we need to be able to unwind to it, so
+     store the current register stack pointer.  Also store the return
+     address if we do that.  */
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    stack_space_to_allocate += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    /* If we do have a saved return-address slot, add room for it.  */
+    stack_space_to_allocate += 8;
+
+  /* Make sure we don't get an unaligned stack.  */
+  if ((stack_space_to_allocate % 8) != 0)
+    internal_error ("stack frame not a multiple of 8 bytes: %d",
+                   stack_space_to_allocate);
+
+  if (current_function_pretend_args_size)
+    {
+      int mmix_first_vararg_reg
+       = (MMIX_FIRST_INCOMING_ARG_REGNUM
+          + (MMIX_MAX_ARGS_IN_REGS
+             - current_function_pretend_args_size / 8));
+
+      for (regno
+            = MMIX_FIRST_INCOMING_ARG_REGNUM + MMIX_MAX_ARGS_IN_REGS - 1;
+          regno >= mmix_first_vararg_reg;
+          regno--)
+       {
+         if (offset < 0)
+           {
+             HOST_WIDE_INT stack_chunk
+               = stack_space_to_allocate > (256 - 8)
+               ? (256 - 8) : stack_space_to_allocate;
+
+             mmix_emit_sp_add (-stack_chunk);
+             offset += stack_chunk;
+             stack_space_to_allocate -= stack_chunk;
+           }
+
+         /* These registers aren't actually saved (as in "will be
+            restored"), so don't tell DWARF2 they're saved.  */
+         emit_move_insn (gen_rtx_MEM (DImode,
+                                      plus_constant (stack_pointer_rtx,
+                                                     offset)),
+                         gen_rtx_REG (DImode, regno));
+         offset -= 8;
+       }
+    }
+
+  /* Store the frame-pointer.  */
+
+  if (frame_pointer_needed)
+    {
+      rtx insn;
+
+      if (offset < 0)
+       {
+         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
+         HOST_WIDE_INT stack_chunk
+           = stack_space_to_allocate > (256 - 8 - 8)
+           ? (256 - 8 - 8) : stack_space_to_allocate;
+
+         mmix_emit_sp_add (-stack_chunk);
+
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
+
+      insn = emit_move_insn (gen_rtx_MEM (DImode,
+                                         plus_constant (stack_pointer_rtx,
+                                                        offset)),
+                            hard_frame_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      insn = emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+                                   stack_pointer_rtx,
+                                   GEN_INT (offset + 8)));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      offset -= 8;
+    }
+
+  if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    {
+      rtx tmpreg, retreg;
+      rtx insn;
+
+      /* Store the return-address, if one is needed on the stack.  We
+        usually store it in a register when needed, but that doesn't work
+        with -fexceptions.  */
+
+      if (offset < 0)
+       {
+         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
+         HOST_WIDE_INT stack_chunk
+           = stack_space_to_allocate > (256 - 8 - 8)
+           ? (256 - 8 - 8) : stack_space_to_allocate;
+
+         mmix_emit_sp_add (-stack_chunk);
+
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
+
+      tmpreg = gen_rtx_REG (DImode, 255);
+      retreg = gen_rtx_REG (DImode, MMIX_rJ_REGNUM);
+
+      /* Dwarf2 code is confused by the use of a temporary register for
+        storing the return address, so we have to express it as a note,
+        which we attach to the actual store insn.  */
+      emit_move_insn (tmpreg, retreg);
+
+      insn = emit_move_insn (gen_rtx_MEM (DImode,
+                                         plus_constant (stack_pointer_rtx,
+                                                        offset)),
+                            tmpreg);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      REG_NOTES (insn)
+       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                            gen_rtx_SET (VOIDmode,
+                                         gen_rtx_MEM (DImode,
+                                                      plus_constant (stack_pointer_rtx,
+                                                                     offset)),
+                                         retreg),
+                            REG_NOTES (insn));
+
+      offset -= 8;
+    }
+  else if (MMIX_CFUN_HAS_LANDING_PAD)
+    offset -= 8;
+
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    {
+      /* Store the register defining the numbering of local registers, so
+        we know how long to unwind the register stack.  */
+
+      if (offset < 0)
+       {
+         /* Get 8 less than otherwise, since we need to reach offset + 8.  */
+         HOST_WIDE_INT stack_chunk
+           = stack_space_to_allocate > (256 - 8 - 8)
+           ? (256 - 8 - 8) : stack_space_to_allocate;
+
+         mmix_emit_sp_add (-stack_chunk);
+
+         offset += stack_chunk;
+         stack_space_to_allocate -= stack_chunk;
+       }
+
+      /* We don't tell dwarf2 about this one; we just have it to unwind
+        the register stack at landing pads.  FIXME: It's a kludge because
+        we can't describe the effect of the PUSHJ and PUSHGO insns on the
+        register stack at the moment.  Best thing would be to handle it
+        like stack-pointer offsets.  Better: some hook into dwarf2out.c
+        to produce DW_CFA_expression:s that specify the increment of rO,
+        and unwind it at eh_return (preferred) or at the landing pad.
+        Then saves to $0..$G-1 could be specified through that register.  */
+
+      emit_move_insn (gen_rtx_REG (DImode, 255),
+                     gen_rtx_REG (DImode,
+                                  MMIX_rO_REGNUM));
+      emit_move_insn (gen_rtx_MEM (DImode,
+                                  plus_constant (stack_pointer_rtx, offset)),
+                     gen_rtx_REG (DImode, 255));
+      offset -= 8;
+    }
+
+  /* After the return-address and the frame-pointer, we have the local
+     variables.  They're the ones that may have an "unaligned" size.  */
+  offset -= (locals_size + 7) & ~7;
+
+  /* Now store all registers that are global, i.e. not saved by the
+     register file machinery.
+
+     It is assumed that the frame-pointer is one of these registers, so it
+     is explicitly excluded in the count.  */
+
+  for (regno = 255;
+       regno >= MMIX_FIRST_GLOBAL_REGNUM;
+       regno--)
+    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && regs_ever_live[regno] && ! call_used_regs[regno])
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      {
+       rtx insn;
+
+       if (offset < 0)
+         {
+           HOST_WIDE_INT stack_chunk
+             = (stack_space_to_allocate > (256 - offset - 8)
+                ? (256 - offset - 8) : stack_space_to_allocate);
+
+           mmix_emit_sp_add (-stack_chunk);
+           offset += stack_chunk;
+           stack_space_to_allocate -= stack_chunk;
+         }
+
+       insn = emit_move_insn (gen_rtx_MEM (DImode,
+                                           plus_constant (stack_pointer_rtx,
+                                                          offset)),
+                              gen_rtx_REG (DImode, regno));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       offset -= 8;
+      }
+
+  /* Finally, allocate room for outgoing args and local vars if room
+     wasn't allocated above.  */
+  if (stack_space_to_allocate)
+    mmix_emit_sp_add (-stack_space_to_allocate);
+}
+
+/* Expands the function epilogue into RTX.  */
+
+void
+mmix_expand_epilogue ()
+{
+  HOST_WIDE_INT locals_size = get_frame_size ();
+  int regno;
+  HOST_WIDE_INT stack_space_to_deallocate
+    = (current_function_outgoing_args_size
+       + current_function_pretend_args_size
+       + locals_size + 7) & ~7;
+
+  /* The assumption that locals_size fits in an int is asserted in
+     mmix_expand_prologue.  */
+
+  /* The first address to access is beyond the outgoing_args area.  */
+  int offset = current_function_outgoing_args_size;
+
+  /* Add the space for global non-register-stack registers.
+     It is assumed that the frame-pointer register can be one of these
+     registers, in which case it is excluded from the count when needed.  */
+  for (regno = 255;
+       regno >= MMIX_FIRST_GLOBAL_REGNUM;
+       regno--)
+    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && regs_ever_live[regno] && !call_used_regs[regno])
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      stack_space_to_deallocate += 8;
+
+  /* Add in the space for register stack-pointer.  If so, always add room
+     for the saved PC.  */
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    stack_space_to_deallocate += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    /* If we have a saved return-address slot, add it in.  */
+    stack_space_to_deallocate += 8;
+
+  /* Add in the frame-pointer.  */
+  if (frame_pointer_needed)
+    stack_space_to_deallocate += 8;
+
+  /* Make sure we don't get an unaligned stack.  */
+  if ((stack_space_to_deallocate % 8) != 0)
+    internal_error ("stack frame not a multiple of octabyte: %d",
+                   stack_space_to_deallocate);
+
+  /* We will add back small offsets to the stack pointer as we go.
+     First, we restore all registers that are global, i.e. not saved by
+     the register file machinery.  */
+
+  for (regno = MMIX_FIRST_GLOBAL_REGNUM;
+       regno <= 255;
+       regno++)
+    if (((regno != MMIX_FRAME_POINTER_REGNUM || !frame_pointer_needed)
+        && regs_ever_live[regno] && !call_used_regs[regno])
+       || IS_MMIX_EH_RETURN_DATA_REG (regno))
+      {
+       if (offset > 255)
+         {
+           mmix_emit_sp_add (offset);
+           stack_space_to_deallocate -= offset;
+           offset = 0;
+         }
+
+       emit_move_insn (gen_rtx_REG (DImode, regno),
+                       gen_rtx_MEM (DImode,
+                                    plus_constant (stack_pointer_rtx,
+                                                   offset)));
+       offset += 8;
+      }
+
+  /* Here is where the local variables were.  As in the prologue, they
+     might be of an unaligned size.  */
+  offset += (locals_size + 7) & ~7;
+
+
+  /* The saved register stack pointer is just below the frame-pointer
+     register.  We don't need to restore it "manually"; the POP
+     instruction does that.  */
+  if (MMIX_CFUN_HAS_LANDING_PAD)
+    offset += 16;
+  else if (MMIX_CFUN_NEEDS_SAVED_EH_RETURN_ADDRESS)
+    /* The return-address slot is just below the frame-pointer register.
+       We don't need to restore it because we don't really use it.  */
+    offset += 8;
+
+  /* Get back the old frame-pointer-value.  */
+  if (frame_pointer_needed)
+    {
+      if (offset > 255)
+       {
+         mmix_emit_sp_add (offset);
+
+         stack_space_to_deallocate -= offset;
+         offset = 0;
+       }
+
+      emit_move_insn (hard_frame_pointer_rtx,
+                     gen_rtx_MEM (DImode,
+                                  plus_constant (stack_pointer_rtx,
+                                                 offset)));
+      offset += 8;
+    }
+
+  /* We do not need to restore pretended incoming args, just add back
+     offset to sp.  */
+  if (stack_space_to_deallocate != 0)
+    mmix_emit_sp_add (stack_space_to_deallocate);
+
+  if (current_function_calls_eh_return)
+    /* Adjust the (normal) stack-pointer to that of the receiver.
+       FIXME: It would be nice if we could also adjust the register stack
+       here, but we need to express it through DWARF 2 too.  */
+    emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+                          gen_rtx_REG (DImode,
+                                       MMIX_EH_RETURN_STACKADJ_REGNUM)));
+}
+
 /* Output an optimal sequence for setting a register to a specific
    constant.  Used in an alternative for const_ints in movdi, and when
    using large stack-frame offsets.
@@ -2884,6 +2798,48 @@ mmix_gen_compare_reg (code, x, y)
 
 /* Local (static) helper functions.  */
 
+static void
+mmix_emit_sp_add (offset)
+     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.  */
 
index 7280a3e..d3dad13 100644 (file)
@@ -49,6 +49,7 @@ Boston, MA 02111-1307, USA.  */
 #define MMIX_HIMULT_REGNUM 258
 #define MMIX_REMAINDER_REGNUM 260
 #define MMIX_ARG_POINTER_REGNUM 261
+#define MMIX_rO_REGNUM 262
 #define MMIX_LAST_STACK_REGISTER_REGNUM 31
 
 /* Four registers; "ideally, these registers should be call-clobbered", so
@@ -92,6 +93,7 @@ struct machine_function GTY(())
  {
    int has_landing_pad;
    int highest_saved_stack_register;
+   int in_prologue;
  };
 
 /* For these target macros, there is no generic documentation here.  You
@@ -360,13 +362,13 @@ extern int target_flags;
 
 /* Node: Register Basics */
 /* We tell GCC about all 256 general registers, and we also include
-   rD, rE, rH, rJ and rR (in that order) so we can describe what insns
+   rD, rE, rH, rJ, rR and rO (in that order) so we can describe what insns
    clobber them.  We use a faked register for the argument pointer.  It is
    always eliminated towards the frame-pointer or the stack-pointer, never
    output in assembly.  Any fixed register would do for this, like $255,
    but future debugging is easier when using a separate register.  It
    counts as a global register for pseudorandom reasons.  */
-#define FIRST_PSEUDO_REGISTER 262
+#define FIRST_PSEUDO_REGISTER 263
 
 /* We treat general registers with no assigned purpose as fixed.  The
    stack pointer, $254, is also fixed.  Register $255 is referred to as a
@@ -390,7 +392,7 @@ extern int target_flags;
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
    1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, \
-   1, 1, 0, 0, 0, 1 \
+   1, 1, 0, 0, 0, 1, 1 \
  }
 
 /* General registers are fixed and therefore "historically" marked
@@ -414,19 +416,23 @@ extern int target_flags;
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, \
-   1, 1, 1, 1, 1, 1 \
+   1, 1, 1, 1, 1, 1, 1 \
  }
 
 #define CONDITIONAL_REGISTER_USAGE mmix_conditional_register_usage ()
 
-/* No LOCAL_REGNO, INCOMING_REGNO or OUTGOING_REGNO, since those macros
-   are not usable for MMIX: it doesn't have a fixed register window size.
-   FIXME: Perhaps we should say something about $0..$15 may sometimes be
-   the incoming $16..$31.  Those macros need better documentation; it
-   looks like they're just bogus and that FUNCTION_INCOMING_ARG_REGNO_P
-   and FUNCTION_OUTGOING_VALUE should be used where they're used.  For the
+/* No INCOMING_REGNO or OUTGOING_REGNO, since those macros are not usable
+   for MMIX: it doesn't have a fixed register window size.  FIXME: Perhaps
+   we should say something about $0..$15 may sometimes be the incoming
+   $16..$31.  Those macros need better documentation; it looks like
+   they're just bogus and that FUNCTION_INCOMING_ARG_REGNO_P and
+   FUNCTION_OUTGOING_VALUE should be used where they're used.  For the
    moment, do nothing; things seem to work anyway.  */
 
+/* Defining LOCAL_REGNO is necessary in presence of prologue/epilogue,
+   else GCC will be confused that those registers aren't saved and
+   restored.  */
+#define LOCAL_REGNO(REGNO) mmix_local_regno (REGNO)
 
 /* Node: Allocation Order */
 
@@ -474,7 +480,7 @@ extern int target_flags;
    232, 233, 234, 235, 236, 237, 238, 239,     \
    240, 241, 242, 243, 244, 245, 246,          \
                                                \
-   254, 255, 256, 257, 261                     \
+   254, 255, 256, 257, 261, 262                        \
  }
 
 /* As a convenience, we put this nearby, for ease of comparison.
@@ -529,7 +535,7 @@ extern int target_flags;
    216, 217, 218, 219, 220, 221, 222, 223,     \
    224, 225, 226, 227, 228, 229, 230,          \
                                                \
-   254, 255, 256, 257, 261                     \
+   254, 255, 256, 257, 261, 262                        \
  }
 
 /* The default one.  */
@@ -573,8 +579,8 @@ enum reg_class
   {~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0x20},      \
   {0, 0, 0, 0, 0, 0, 0, 0, 0x10},              \
   {0, 0, 0, 0, 0, 0, 0, 0, 4},                 \
-  {0, 0, 0, 0, 0, 0, 0, 0, 0x3f},              \
-  {~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0x3f}}
+  {0, 0, 0, 0, 0, 0, 0, 0, 0x7f},              \
+  {~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, 0x7f}}
 
 #define REGNO_REG_CLASS(REGNO)                                 \
  ((REGNO) <= MMIX_LAST_GENERAL_REGISTER                                \
@@ -1058,11 +1064,11 @@ typedef struct { int regs; int lib; int now_varargs; } CUMULATIVE_ARGS;
   "$232", "$233", "$234", "$235", "$236", "$237", "$238", "$239",      \
   "$240", "$241", "$242", "$243", "$244", "$245", "$246", "$247",      \
   "$248", "$249", "$250", "$251", "$252", "$253", "$254", "$255",      \
-  ":rD",  ":rE",  ":rH",  ":rJ",  ":rR",  "ap_!BAD!"}
+  ":rD",  ":rE",  ":rH",  ":rJ",  ":rR",  "ap_!BAD!", ":rO"}
 
 #define ADDITIONAL_REGISTER_NAMES                      \
  {{"sp", 254}, {":sp", 254}, {"rD", 256}, {"rE", 257}, \
-  {"rH", 258}, {"rJ", MMIX_rJ_REGNUM}}
+  {"rH", 258}, {"rJ", MMIX_rJ_REGNUM}, {"rO", MMIX_rO_REGNUM}}
 
 #define PRINT_OPERAND(STREAM, X, CODE) \
  mmix_print_operand (STREAM, X, CODE)
index 024395b..88ae514 100644 (file)
@@ -988,7 +988,8 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
      in the call, and we set it back after every call (all but one setting
      will be optimized away), integrity is maintained.  */
   operands[3]
-    = get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
+    = mmix_get_hard_reg_initial_val (Pmode,
+                                    MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
 
   /* FIXME: There's a bug in gcc which causes NULL to be passed as
      operand[2] when we get out of registers, which later confuses gcc.
@@ -1014,7 +1015,8 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
      in the call, and we set it back after every call (all but one setting
      will be optimized away), integrity is maintained.  */
   operands[4]
-    = get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
+    = mmix_get_hard_reg_initial_val (Pmode,
+                                    MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
 
   /* FIXME: See 'call'.  */
   if (operands[3] == NULL_RTX)
@@ -1067,11 +1069,30 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
 ;; I hope untyped_call and untyped_return are not needed for MMIX.
 ;; Users of Objective C will notice.
 
-(define_insn "return"
+; Generated by GCC.
+(define_expand "return"
   [(return)]
   "mmix_use_simple_return ()"
+  "")
+
+; Generated by the epilogue expander.
+(define_insn "*expanded_return"
+  [(return)]
+  ""
   "POP %.,0")
 
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  "mmix_expand_prologue (); DONE;")
+
+; Note that the (return) from the expander itself is always the last insn
+; in the epilogue.
+(define_expand "epilogue"
+  [(return)]
+  ""
+  "mmix_expand_epilogue ();")
+
 (define_insn "nop"
   [(const_int 0)]
   ""
@@ -1111,7 +1132,8 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
   "
 {
   operands[0]
-    = get_hard_reg_initial_val (Pmode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
+    = mmix_get_hard_reg_initial_val (Pmode,
+                                    MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
 
   /* Mark this function as containing a landing-pad.  */
   cfun->machine->has_landing_pad = 1;