]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/fr30/fr30.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / fr30 / fr30.c
index 261f3665325de5138206b61d1efc1552d53fa3ac..e7f2e3cfd8640c55b08445060e4533d2637e3668 100644 (file)
@@ -1,44 +1,46 @@
 /* FR30 specific functions.
-   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2008
+   Free Software Foundation, Inc.
    Contributed by Cygnus Solutions.
 
-This file is part of GNU CC.
+   This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
-/*}}}*/
 /*{{{  Includes */ 
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "recog.h"
 #include "tree.h"
+#include "output.h"
 #include "expr.h"
 #include "obstack.h"
 #include "except.h"
 #include "function.h"
+#include "toplev.h"
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
@@ -90,7 +92,7 @@ struct rtx_def * fr30_compare_op1;
                                    SP ->|                       |  /  
                                         +-----------------------+    
    
-   Note, AP is a fake hard register.  It will be eliminated in favour of
+   Note, AP is a fake hard register.  It will be eliminated in favor of
    SP or FP as appropriate.
 
    Note, Some or all of the stack sections above may be omitted if they 
@@ -100,16 +102,16 @@ struct rtx_def * fr30_compare_op1;
    save masks, and offsets for the current function.  */
 struct fr30_frame_info
 {
-  unsigned int total_size;     /* # Bytes that the entire frame takes up. */
-  unsigned int pretend_size;   /* # Bytes we push and pretend caller did. */
-  unsigned int args_size;      /* # Bytes that outgoing arguments take up. */
-  unsigned int reg_size;       /* # Bytes needed to store regs. */
-  unsigned int var_size;       /* # Bytes that variables take up. */
+  unsigned int total_size;     /* # Bytes that the entire frame takes up.  */
+  unsigned int pretend_size;   /* # Bytes we push and pretend caller did.  */
+  unsigned int args_size;      /* # Bytes that outgoing arguments take up.  */
+  unsigned int reg_size;       /* # Bytes needed to store regs.  */
+  unsigned int var_size;       /* # Bytes that variables take up.  */
   unsigned int frame_size;      /* # Bytes in current frame.  */
-  unsigned int gmask;          /* Mask of saved registers. */
-  unsigned int save_fp;                /* Nonzero if frame pointer must be saved. */
-  unsigned int save_rp;                /* Nonzero if return popinter must be saved. */
-  int          initialised;    /* Nonzero if frame size already calculated. */
+  unsigned int gmask;          /* Mask of saved registers.  */
+  unsigned int save_fp;                /* Nonzero if frame pointer must be saved.  */
+  unsigned int save_rp;                /* Nonzero if return pointer must be saved.  */
+  int          initialised;    /* Nonzero if frame size already calculated.  */
 };
 
 /* Current frame information calculated by fr30_compute_frame_size().  */
@@ -118,8 +120,12 @@ static struct fr30_frame_info      current_frame_info;
 /* Zero structure to initialize current_frame_info.  */
 static struct fr30_frame_info  zero_frame_info;
 
-static rtx fr30_pass_by_reference PARAMS ((tree, tree));
-static rtx fr30_pass_by_value PARAMS ((tree, tree));
+static void fr30_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+                                        tree, int *, int);
+static bool fr30_must_pass_in_stack (enum machine_mode, const_tree);
+static int fr30_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                  tree, bool);
+
 
 #define FRAME_POINTER_MASK     (1 << (FRAME_POINTER_REGNUM))
 #define RETURN_POINTER_MASK    (1 << (RETURN_POINTER_REGNUM))
@@ -130,31 +136,41 @@ static rtx fr30_pass_by_value PARAMS ((tree, tree));
 #define MUST_SAVE_REGISTER(regno)      \
   (   (regno) != RETURN_POINTER_REGNUM \
    && (regno) != FRAME_POINTER_REGNUM  \
-   &&   regs_ever_live [regno]         \
+   && df_regs_ever_live_p (regno)      \
    && ! call_used_regs [regno]         )
 
-#define MUST_SAVE_FRAME_POINTER         (regs_ever_live [FRAME_POINTER_REGNUM]  || frame_pointer_needed)
-#define MUST_SAVE_RETURN_POINTER (regs_ever_live [RETURN_POINTER_REGNUM] || current_function_profile)
+#define MUST_SAVE_FRAME_POINTER         (df_regs_ever_live_p (FRAME_POINTER_REGNUM)  || frame_pointer_needed)
+#define MUST_SAVE_RETURN_POINTER (df_regs_ever_live_p (RETURN_POINTER_REGNUM) || crtl->profile)
 
 #if UNITS_PER_WORD == 4
 #define WORD_ALIGN(SIZE) (((SIZE) + 3) & ~3)
 #endif
 \f
 /* Initialize the GCC target structure.  */
-#undef TARGET_ASM_ALIGNED_HI_OP
+#undef  TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
-#undef TARGET_ASM_ALIGNED_SI_OP
+#undef  TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
 
+#undef  TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+#undef  TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
+#undef  TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES fr30_arg_partial_bytes
+
+#undef  TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS fr30_setup_incoming_varargs
+#undef  TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK fr30_must_pass_in_stack
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Returns the number of bytes offset between FROM_REG and TO_REG
    for the current function.  As a side effect it fills in the 
    current_frame_info structure, if the data is available.  */
 unsigned int
-fr30_compute_frame_size (from_reg, to_reg)
-     int from_reg;
-     int to_reg;
+fr30_compute_frame_size (int from_reg, int to_reg)
 {
   int          regno;
   unsigned int         return_value;
@@ -165,8 +181,8 @@ fr30_compute_frame_size (from_reg, to_reg)
   unsigned int         gmask;
 
   var_size     = WORD_ALIGN (get_frame_size ());
-  args_size    = WORD_ALIGN (current_function_outgoing_args_size);
-  pretend_size = current_function_pretend_args_size;
+  args_size    = WORD_ALIGN (crtl->outgoing_args_size);
+  pretend_size = crtl->args.pretend_args_size;
 
   reg_size     = 0;
   gmask                = 0;
@@ -217,7 +233,7 @@ fr30_compute_frame_size (from_reg, to_reg)
    insn to prevent such scheduling.  */
 
 void
-fr30_expand_prologue ()
+fr30_expand_prologue (void)
 {
   int regno;
   rtx insn;
@@ -226,9 +242,7 @@ fr30_expand_prologue ()
     fr30_compute_frame_size (0, 0);
 
   /* This cases shouldn't happen.  Catch it now.  */
-  if (current_frame_info.total_size == 0
-      && current_frame_info.gmask)
-    abort ();
+  gcc_assert (current_frame_info.total_size || !current_frame_info.gmask);
 
   /* Allocate space for register arguments if this is a variadic function.  */
   if (current_frame_info.pretend_size)
@@ -294,7 +308,7 @@ fr30_expand_prologue ()
                     G++ testsuite.  */
                  if (! frame_pointer_needed
                      && GET_CODE (part) == SET
-                     && REGNO (SET_DEST (part)) == HARD_FRAME_POINTER_REGNUM)
+                     && SET_DEST (part) == hard_frame_pointer_rtx)
                    RTX_FRAME_RELATED_P (part) = 0;
                  else
                    RTX_FRAME_RELATED_P (part) = 1;
@@ -322,7 +336,8 @@ fr30_expand_prologue ()
     ; /* Nothing to do.  */
   else if (current_frame_info.frame_size <= 512)
     {
-      insn = emit_insn (gen_add_to_stack (GEN_INT (- current_frame_info.frame_size)));
+      insn = emit_insn (gen_add_to_stack
+                        (GEN_INT (- (signed) current_frame_info.frame_size)));
       RTX_FRAME_RELATED_P (insn) = 1;
     }
   else
@@ -334,7 +349,7 @@ fr30_expand_prologue ()
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  if (current_function_profile)
+  if (crtl->profile)
     emit_insn (gen_blockage ());
 }
 
@@ -345,14 +360,13 @@ fr30_expand_prologue ()
    In some cases, it might be necessary to emit a barrier instruction as the
    first insn to prevent such scheduling.  */
 void
-fr30_expand_epilogue ()
+fr30_expand_epilogue (void)
 {
   int regno;
 
   /* Perform the inversion operations of the prologue.  */
-  if (! current_frame_info.initialised)
-    abort ();
-
+  gcc_assert (current_frame_info.initialised);
+  
   /* Pop local variables and arguments off the stack.
      If frame_pointer_needed is TRUE then the frame pointer register
      has actually been used as a frame pointer, and we can recover
@@ -404,29 +418,25 @@ fr30_expand_epilogue ()
    ARG_REGS_USED_SO_FAR has *not* been updated for the last named argument
    which has type TYPE and mode MODE, and we rely on this fact.  */
 void
-fr30_setup_incoming_varargs (arg_regs_used_so_far, int_mode, type, pretend_size)
-     CUMULATIVE_ARGS arg_regs_used_so_far;
-     int             int_mode;
-     tree            type ATTRIBUTE_UNUSED;
-     int *           pretend_size;
+fr30_setup_incoming_varargs (CUMULATIVE_ARGS *arg_regs_used_so_far,
+                            enum machine_mode mode,
+                            tree type ATTRIBUTE_UNUSED,
+                            int *pretend_size,
+                            int second_time ATTRIBUTE_UNUSED)
 {
-  enum machine_mode mode = (enum machine_mode)int_mode;
-  int               size;
+  int size;
 
-  
   /* All BLKmode values are passed by reference.  */
-  if (mode == BLKmode)
-    abort ();
-
-#if STRICT_ARGUMENT_NAMING
-  /* We must treat `__builtin_va_alist' as an anonymous arg.
-     But otherwise if STRICT_ARGUMENT_NAMING is true then the
-     last named arg must not be treated as an anonymous arg. */
-  if (! current_function_varargs)
-    arg_regs_used_so_far += fr30_num_arg_regs (int_mode, type);
-#endif
-  
-  size = FR30_NUM_ARG_REGS - arg_regs_used_so_far;
+  gcc_assert (mode != BLKmode);
+
+  /* ??? This run-time test as well as the code inside the if
+     statement is probably unnecessary.  */
+  if (targetm.calls.strict_argument_naming (arg_regs_used_so_far))
+    /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named
+       arg must not be treated as an anonymous arg.  */
+    arg_regs_used_so_far += fr30_num_arg_regs (mode, type);
+
+  size = FR30_NUM_ARG_REGS - (* arg_regs_used_so_far);
 
   if (size <= 0)
     return;
@@ -440,9 +450,7 @@ fr30_setup_incoming_varargs (arg_regs_used_so_far, int_mode, type, pretend_size)
 /* Print a memory address as an operand to reference that memory location.  */
 
 void
-fr30_print_operand_address (stream, address)
-     FILE * stream;
-     rtx    address;
+fr30_print_operand_address (FILE *stream, rtx address)
 {
   switch (GET_CODE (address))
     {
@@ -461,10 +469,7 @@ fr30_print_operand_address (stream, address)
 /* Print an operand.  */
 
 void
-fr30_print_operand (file, x, code)
-     FILE * file;
-     rtx    x;
-     int    code;
+fr30_print_operand (FILE *file, rtx x, int code)
 {
   rtx x0;
   
@@ -538,7 +543,7 @@ fr30_print_operand (file, x, code)
 
          val &= 0xff;
 
-         fprintf (file, "%d", val);
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
        }
       return;
       
@@ -548,7 +553,7 @@ fr30_print_operand (file, x, code)
          || INTVAL (x) > 32)
        output_operand_lossage ("fr30_print_operand: invalid %%x code");
       else
-       fprintf (file, "%d", INTVAL (x) - 16);
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) - 16);
       return;
 
     case 'F':
@@ -556,10 +561,11 @@ fr30_print_operand (file, x, code)
        output_operand_lossage ("fr30_print_operand: invalid %%F code");
       else
        {
-         REAL_VALUE_TYPE d;
+         char str[30];
 
-         REAL_VALUE_FROM_CONST_DOUBLE (d, x);
-         fprintf (file, "%.8f", d);
+         real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x),
+                          sizeof (str), 0, 1);
+         fputs (str, file);
        }
       return;
       
@@ -585,8 +591,7 @@ fr30_print_operand (file, x, code)
       switch (GET_CODE (x0))
        {
        case REG:
-         if ((unsigned) REGNO (x0) >= ARRAY_SIZE (reg_names))
-           abort ();
+         gcc_assert ((unsigned) REGNO (x0) < ARRAY_SIZE (reg_names));
          fprintf (file, "@%s", reg_names [REGNO (x0)]);
          break;
 
@@ -609,7 +614,7 @@ fr30_print_operand (file, x, code)
                  debug_rtx (x);
                  output_operand_lossage ("fr30_print_operand: unhandled MEM");
                }
-             fprintf (file, "@(r14, #%d)", val);
+             fprintf (file, "@(r14, #" HOST_WIDE_INT_PRINT_DEC ")", val);
            }
          else
            {
@@ -620,7 +625,7 @@ fr30_print_operand (file, x, code)
                  debug_rtx (x);
                  output_operand_lossage ("fr30_print_operand: unhandled MEM");
                }
-             fprintf (file, "@(r15, #%d)", val);
+             fprintf (file, "@(r15, #" HOST_WIDE_INT_PRINT_DEC ")", val);
            }
          break;
          
@@ -661,17 +666,27 @@ fr30_print_operand (file, x, code)
 /*}}}*/
 /*{{{  Function arguments */ 
 
+/* Return true if we should pass an argument on the stack rather than
+   in registers.  */
+
+static bool
+fr30_must_pass_in_stack (enum machine_mode mode, const_tree type)
+{
+  if (mode == BLKmode)
+    return true;
+  if (type == NULL)
+    return false;
+  return AGGREGATE_TYPE_P (type);
+}
+
 /* Compute the number of word sized registers needed to hold a
    function argument of mode INT_MODE and tree type TYPE.  */
 int
-fr30_num_arg_regs (int_mode, type)
-     int int_mode;
-     tree type;
+fr30_num_arg_regs (enum machine_mode mode, tree type)
 {
-  enum machine_mode mode = (enum machine_mode) int_mode;
   int size;
 
-  if (MUST_PASS_IN_STACK (mode, type))
+  if (targetm.calls.must_pass_in_stack (mode, type))
     return 0;
 
   if (type && mode == BLKmode)
@@ -682,25 +697,21 @@ fr30_num_arg_regs (int_mode, type)
   return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 }
 
-/* Implements the FUNCTION_ARG_PARTIAL_NREGS macro.
-   Returns the number of argument registers required to hold *part* of
-   a parameter of machine mode MODE and tree type TYPE (which may be
-   NULL if the type is not known).  If the argument fits entirly in
-   the argument registers, or entirely on the stack, then 0 is returned.
+/* Returns the number of bytes in which *part* of a parameter of machine
+   mode MODE and tree type TYPE (which may be NULL if the type is not known).
+   If the argument fits entirely in the argument registers, or entirely on
+   the stack, then 0 is returned.
    CUM is the number of argument registers already used by earlier
    parameters to the function.  */
 
-int
-fr30_function_arg_partial_nregs (cum, int_mode, type, named)
-     CUMULATIVE_ARGS cum;
-     int int_mode;
-     tree type;
-     int named;
+static int
+fr30_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                       tree type, bool named)
 {
-  /* Unnamed arguments, ie those that are prototyped as ...
+  /* Unnamed arguments, i.e. those that are prototyped as ...
      are always passed on the stack.
      Also check here to see if all the argument registers are full.  */
-  if (named == 0 || cum >= FR30_NUM_ARG_REGS)
+  if (named == 0 || *cum >= FR30_NUM_ARG_REGS)
     return 0;
 
   /* Work out how many argument registers would be needed if this
@@ -709,87 +720,10 @@ fr30_function_arg_partial_nregs (cum, int_mode, type, named)
      are needed because the parameter must be passed on the stack)
      then return zero, as this parameter does not require partial
      register, partial stack stack space.  */
-  if (cum + fr30_num_arg_regs (int_mode, type) <= FR30_NUM_ARG_REGS)
+  if (*cum + fr30_num_arg_regs (mode, type) <= FR30_NUM_ARG_REGS)
     return 0;
   
-  /* Otherwise return the number of registers that would be used.  */
-  return FR30_NUM_ARG_REGS - cum;
-}
-
-static rtx
-fr30_pass_by_reference (valist, type)
-     tree valist;
-     tree type;
-{
-  tree type_ptr;
-  tree type_ptr_ptr;
-  tree t;
-  
-  type_ptr     = build_pointer_type (type);
-  type_ptr_ptr = build_pointer_type (type_ptr);
-  
-  t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, build_int_2 (UNITS_PER_WORD, 0));
-  TREE_SIDE_EFFECTS (t) = 1;
-  t = build1 (NOP_EXPR, type_ptr_ptr, t);
-  TREE_SIDE_EFFECTS (t) = 1;
-  t = build1 (INDIRECT_REF, type_ptr, t);
-  
-  return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
-}
-
-static rtx
-fr30_pass_by_value (valist, type)
-     tree valist;
-     tree type;
-{
-  HOST_WIDE_INT size = int_size_in_bytes (type);
-  HOST_WIDE_INT rsize;
-  rtx addr_rtx;
-  tree t;
-
-  if ((size % UNITS_PER_WORD) == 0)
-    {
-      t = build (POSTINCREMENT_EXPR, va_list_type_node, valist, build_int_2 (size, 0));
-      TREE_SIDE_EFFECTS (t) = 1;
-      
-      return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
-    }
-
-  rsize = (size + UNITS_PER_WORD - 1) & - UNITS_PER_WORD;
-      
-  /* Care for bigendian correction on the aligned address.  */
-  t = build (PLUS_EXPR, ptr_type_node, valist, build_int_2 (rsize - size, 0));
-  addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
-  addr_rtx = copy_to_reg (addr_rtx);
-      
-  /* Increment AP.  */
-  t = build (PLUS_EXPR, va_list_type_node, valist, build_int_2 (rsize, 0));
-  t = build (MODIFY_EXPR, va_list_type_node, valist, t);
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
-  
-  return addr_rtx;
-}
-
-/* Implement `va_arg'.  */
-
-rtx
-fr30_va_arg (valist, type)
-     tree valist;
-     tree type;
-{
-  HOST_WIDE_INT size;
-  
-  if (AGGREGATE_TYPE_P (type))
-    return fr30_pass_by_reference (valist, type);
-  
-  size = int_size_in_bytes (type);
-
-  if ((size % sizeof (int)) == 0
-      || size < 4)
-    return fr30_pass_by_value (valist, type);
-
-  return fr30_pass_by_reference (valist, type);
+  return (FR30_NUM_ARG_REGS - *cum) * UNITS_PER_WORD;
 }
 
 /*}}}*/
@@ -799,125 +733,10 @@ fr30_va_arg (valist, type)
 #define Mmode enum machine_mode
 #endif
 
-/* Returns true if OPERAND is an integer value suitable for use in
-   an ADDSP instruction.  */
-int
-stack_add_operand (operand, mode)
-     rtx operand;
-     Mmode mode ATTRIBUTE_UNUSED;
-{
-  return
-    (GET_CODE (operand) == CONST_INT
-     && INTVAL (operand) >= -512
-     && INTVAL (operand) <=  508
-     && ((INTVAL (operand) & 3) == 0));
-}
-
-/* Returns true if OPERAND is an integer value suitable for use in
-   an ADD por ADD2 instruction, or if it is a register.  */
-int
-add_immediate_operand (operand, mode)
-     rtx operand;
-     Mmode mode ATTRIBUTE_UNUSED;
-{
-  return
-    (GET_CODE (operand) == REG
-     || (GET_CODE (operand) == CONST_INT
-        && INTVAL (operand) >= -16
-        && INTVAL (operand) <=  15));
-}
-
-/* Returns true if OPERAND is hard register in the range 8 - 15.  */
-int
-high_register_operand (operand, mode)
-     rtx operand;
-     Mmode mode ATTRIBUTE_UNUSED;
-{
-  return
-    (GET_CODE (operand) == REG
-     && REGNO (operand) <= 15
-     && REGNO (operand) >= 8);
-}
-
-/* Returns true if OPERAND is hard register in the range 0 - 7.  */
-int
-low_register_operand (operand, mode)
-     rtx operand;
-     Mmode mode ATTRIBUTE_UNUSED;
-{
-  return
-    (GET_CODE (operand) == REG
-     && REGNO (operand) <= 7);
-}
-
-/* Returns true if OPERAND is suitable for use in a CALL insn.  */
-int
-call_operand (operand, mode)
-     rtx operand;
-     Mmode mode ATTRIBUTE_UNUSED;
-{
-  return (GET_CODE (operand) == MEM
-         && (GET_CODE (XEXP (operand, 0)) == SYMBOL_REF
-             || GET_CODE (XEXP (operand, 0)) == REG));
-}
-
-/* Returns TRUE if OP is a valid operand of a DImode operation.  */
-int
-di_operand (op, mode)
-     rtx op;
-     Mmode mode;
-{
-  if (register_operand (op, mode))
-    return TRUE;
-
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
-    return FALSE;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  switch (GET_CODE (op))
-    {
-    case CONST_DOUBLE:
-    case CONST_INT:
-      return TRUE;
-
-    case MEM:
-      return memory_address_p (DImode, XEXP (op, 0));
-
-    default:
-      return FALSE;
-    }
-}
-
-/* Returns TRUE if OP is a DImode register or MEM.  */
-int
-nonimmediate_di_operand (op, mode)
-     rtx op;
-     Mmode mode;
-{
-  if (register_operand (op, mode))
-    return TRUE;
-
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
-    return FALSE;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  if (GET_CODE (op) == MEM)
-    return memory_address_p (DImode, XEXP (op, 0));
-
-  return FALSE;
-}
-
 /* Returns true iff all the registers in the operands array
    are in descending or ascending order.  */
 int
-fr30_check_multiple_regs (operands, num_operands, descending)
-     rtx * operands;
-     int   num_operands;
-     int   descending;
+fr30_check_multiple_regs (rtx *operands, int num_operands, int descending)
 {
   if (descending)
     {
@@ -953,19 +772,31 @@ fr30_check_multiple_regs (operands, num_operands, descending)
   return 1;
 }
 
+int
+fr30_const_double_is_zero (rtx operand)
+{
+  REAL_VALUE_TYPE d;
+
+  if (operand == NULL || GET_CODE (operand) != CONST_DOUBLE)
+    return 0;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (d, operand);
+
+  return REAL_VALUES_EQUAL (d, dconst0);
+}
+
 /*}}}*/
 /*{{{  Instruction Output Routines  */
 
 /* Output a double word move.
    It must be REG<-REG, REG<-MEM, MEM<-REG or REG<-CONST.
-   On the FR30 we are contrained by the fact that it does not
+   On the FR30 we are constrained by the fact that it does not
    support offsetable addresses, and so we have to load the
    address of the secnd word into the second destination register
    before we can use it.  */
 
 rtx
-fr30_move_double (operands)
-     rtx * operands;
+fr30_move_double (rtx * operands)
 {
   rtx src  = operands[1];
   rtx dest = operands[0];
@@ -997,48 +828,23 @@ fr30_move_double (operands)
        {
          rtx addr = XEXP (src, 0);
          int dregno = REGNO (dest);
-         rtx dest0;
-         rtx dest1;
+         rtx dest0 = operand_subword (dest, 0, TRUE, mode);;
+         rtx dest1 = operand_subword (dest, 1, TRUE, mode);;
          rtx new_mem;
          
-         /* If the high-address word is used in the address, we
-            must load it last.  Otherwise, load it first.  */
-         int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0);
-
-         if (GET_CODE (addr) != REG)
-           abort ();
+         gcc_assert (GET_CODE (addr) == REG);
          
-         dest0 = operand_subword (dest, reverse, TRUE, mode);
-         dest1 = operand_subword (dest, !reverse, TRUE, mode);
-
-         if (reverse)
-           {
-             emit_insn (gen_rtx_SET (VOIDmode, dest1,
-                                     adjust_address (src, SImode, 0)));
-             emit_insn (gen_rtx_SET (SImode, dest0,
-                                     gen_rtx_REG (SImode, REGNO (addr))));
-             emit_insn (gen_rtx_SET (SImode, dest0,
-                                     plus_constant (dest0, UNITS_PER_WORD)));
-
-             new_mem = gen_rtx_MEM (SImode, dest0);
-             MEM_COPY_ATTRIBUTES (new_mem, src);
+         /* Copy the address before clobbering it.  See PR 34174.  */
+         emit_insn (gen_rtx_SET (SImode, dest1, addr));
+         emit_insn (gen_rtx_SET (VOIDmode, dest0,
+                                 adjust_address (src, SImode, 0)));
+         emit_insn (gen_rtx_SET (SImode, dest1,
+                                 plus_constant (dest1, UNITS_PER_WORD)));
+
+         new_mem = gen_rtx_MEM (SImode, dest1);
+         MEM_COPY_ATTRIBUTES (new_mem, src);
              
-             emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem));
-           }
-         else
-           {
-             emit_insn (gen_rtx_SET (VOIDmode, dest0,
-                                     adjust_address (src, SImode, 0)));
-             emit_insn (gen_rtx_SET (SImode, dest1,
-                                     gen_rtx_REG (SImode, REGNO (addr))));
-             emit_insn (gen_rtx_SET (SImode, dest1,
-                                     plus_constant (dest1, UNITS_PER_WORD)));
-
-             new_mem = gen_rtx_MEM (SImode, dest1);
-             MEM_COPY_ATTRIBUTES (new_mem, src);
-             
-             emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
-           }
+         emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
        }
       else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
        {
@@ -1059,14 +865,12 @@ fr30_move_double (operands)
       rtx src0;
       rtx src1;
 
-      if (GET_CODE (addr) != REG)
-       abort ();
-      
+      gcc_assert (GET_CODE (addr) == REG);
+
       src0 = operand_subword (src, 0, TRUE, mode);
       src1 = operand_subword (src, 1, TRUE, mode);
-      
-      emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, 0),
-                             src0));
+
+      emit_move_insn (adjust_address (dest, SImode, 0), src0);
 
       if (REGNO (addr) == STACK_POINTER_REGNUM
          || REGNO (addr) == FRAME_POINTER_REGNUM)
@@ -1076,27 +880,32 @@ fr30_move_double (operands)
       else
        {
          rtx new_mem;
-         
+         rtx scratch_reg_r0 = gen_rtx_REG (SImode, 0);
+
          /* We need a scratch register to hold the value of 'address + 4'.
-            We ought to allow gcc to find one for us, but for now, just
-            push one of the source registers.  */
-         emit_insn (gen_movsi_push (src0));
-         emit_insn (gen_movsi_internal (src0, addr));
-         emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD)));
-         
-         new_mem = gen_rtx_MEM (SImode, src0);
+            We use r0 for this purpose. It is used for example for long
+            jumps and is already marked to not be used by normal register
+            allocation.  */
+         emit_insn (gen_movsi_internal (scratch_reg_r0, addr));
+         emit_insn (gen_addsi_small_int (scratch_reg_r0, scratch_reg_r0,
+                                         GEN_INT (UNITS_PER_WORD)));
+         new_mem = gen_rtx_MEM (SImode, scratch_reg_r0);
          MEM_COPY_ATTRIBUTES (new_mem, dest);
-         
-         emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1));
-         emit_insn (gen_movsi_pop (src0));
+         emit_move_insn (new_mem, src1);
+         emit_insn (gen_blockage ());
        }
     }
   else
     /* This should have been prevented by the constraints on movdi_insn.  */
-    abort ();
-  
-  val = gen_sequence ();
+    gcc_unreachable ();
+
+  val = get_insns ();
   end_sequence ();
 
   return val;
 }
+
+/*}}}*/
+/* Local Variables: */
+/* folded-file: t   */
+/* End:                    */