OSDN Git Service

Add movdi pattern to FR30 port.
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 12 May 2000 20:57:57 +0000 (20:57 +0000)
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 12 May 2000 20:57:57 +0000 (20:57 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33885 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 9eae7dd..a8cdab9 100644 (file)
@@ -1,3 +1,22 @@
+2000-05-12  Nick Clifton  <nickc@cygnus.com>
+
+       * config/fr30/fr30.c (fr30_move_double): New function:  Emit code
+       to move a double word value.
+       (di_operand): New function: Return true if the operand is suitbale
+       for a double word move operation.
+       (nonimmediate_di_operand): New function: Return true if the
+       operand is a DImode register or MEM.
+
+       * config/fr30/fr30.h (PREDICATE_CODES): Add di_operand and
+       nonimmediate_di_operand.
+
+       * config/fr30/fr30-protos.h Add fr30_move_double, di_operand, and
+       nonimmediate_di_operand.
+
+       * config/fr30/fr30.md (movdi): New pattern.  Required because
+       other patterns generate DImode results.
+       (movdi_insn): New pattern.
+
 2000-05-12  Richard Henderson  <rth@cygnus.com>
 
        * config/alpha/alpha.c (struct shadow_summary): Define
index aa18399..e6d3138 100644 (file)
@@ -26,6 +26,7 @@ extern unsigned int fr30_compute_frame_size PARAMS ((int, int));
 extern int   fr30_check_multiple_regs   PARAMS ((rtx *, int, int));
 extern void  fr30_print_operand         PARAMS ((FILE *, rtx, int));
 extern void  fr30_print_operand_address PARAMS ((FILE *, rtx));
+extern rtx   fr30_move_double          PARAMS ((rtx *));
 #ifdef TREE_CODE
 extern rtx   fr30_va_arg                PARAMS ((tree, tree));
 #endif /* TREE_CODE */
@@ -36,6 +37,8 @@ extern int   add_immediate_operand      PARAMS ((rtx, Mmode));
 extern int   high_register_operand      PARAMS ((rtx, Mmode));
 extern int   low_register_operand       PARAMS ((rtx, Mmode));
 extern int   call_operand               PARAMS ((rtx, Mmode));
+extern int   di_operand                PARAMS ((rtx, Mmode));
+extern int   nonimmediate_di_operand   PARAMS ((rtx, Mmode));
 #undef Mmode
 #endif /* HAVE_MACHINE_MODES */
 #endif /* RTX_CODE */
index 26b3d82..68bae05 100644 (file)
@@ -24,10 +24,8 @@ Boston, MA 02111-1307, USA.  */
 /*}}}*/
 /*{{{  Includes */ 
 
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/param.h> /* so that MIn and MAX are defined before machmode.h */
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -44,7 +42,7 @@ Boston, MA 02111-1307, USA.  */
 #include "obstack.h"
 #include "except.h"
 #include "function.h"
-#include "fr30-protos.h"
+#include "tm_p.h"
 
 /*}}}*/
 /*{{{  Function Prologues & Epilogues */ 
@@ -839,8 +837,7 @@ low_register_operand (operand, mode)
 {
   return
     (GET_CODE (operand) == REG
-     && REGNO (operand) <= 7
-     && REGNO (operand) >= 0);
+     && REGNO (operand) <= 7);
 }
 
 /* Returns true if OPERAND is suitable for use in a CALL insn.  */
@@ -854,6 +851,56 @@ call_operand (operand, mode)
              || 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
@@ -864,9 +911,9 @@ fr30_check_multiple_regs (operands, num_operands, descending)
 {
   if (descending)
     {
-      int prev_regno = -1;
+      unsigned int prev_regno = 0;
       
-      while (num_operands--)
+      while (num_operands --)
        {
          if (GET_CODE (operands [num_operands]) != REG)
            return 0;
@@ -879,9 +926,9 @@ fr30_check_multiple_regs (operands, num_operands, descending)
     }
   else
     {
-      int prev_regno = CONDITION_CODE_REGNUM;
+      unsigned int prev_regno = CONDITION_CODE_REGNUM;
       
-      while (num_operands--)
+      while (num_operands --)
        {
          if (GET_CODE (operands [num_operands]) != REG)
            return 0;
@@ -897,6 +944,146 @@ fr30_check_multiple_regs (operands, num_operands, descending)
 }
 
 /*}}}*/
+/*{{{  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
+   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;
+{
+  rtx src  = operands[1];
+  rtx dest = operands[0];
+  enum rtx_code src_code = GET_CODE (src);
+  enum rtx_code dest_code = GET_CODE (dest);
+  enum machine_mode mode = GET_MODE (dest);
+  rtx val;
+
+  start_sequence ();
+
+  if (dest_code == REG)
+    {
+      if (src_code == REG)
+       {
+         int reverse = (REGNO (dest) == REGNO (src) + 1);
+         
+         /* We normally copy the low-numbered register first.  However, if
+            the first register of operand 0 is the same as the second register
+            of operand 1, we must copy in the opposite order.  */
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, reverse, TRUE, mode),
+                                 operand_subword (src,  reverse, TRUE, mode)));
+         
+         emit_insn (gen_rtx_SET (VOIDmode,
+                             operand_subword (dest, !reverse, TRUE, mode),
+                             operand_subword (src,  !reverse, TRUE, mode)));
+       }
+      else if (src_code == MEM)
+       {
+         rtx addr = XEXP (src, 0);
+         int dregno = REGNO (dest);
+         rtx dest0;
+         rtx dest1;
+         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 ();
+         
+         dest0 = operand_subword (dest, reverse, TRUE, mode);
+         dest1 = operand_subword (dest, !reverse, TRUE, mode);
+
+         if (reverse)
+           {
+             emit_insn (gen_rtx_SET (VOIDmode, dest1, change_address (src, SImode, addr)));
+             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);
+             
+             emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem));
+           }
+         else
+           {
+             emit_insn (gen_rtx_SET (VOIDmode, dest0, change_address (src, SImode, addr)));
+             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));
+           }
+       }
+      else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
+       {
+         rtx words[2];
+         split_double (src, &words[0], &words[1]);
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, 0, TRUE, mode),
+                                 words[0]));
+      
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 operand_subword (dest, 1, TRUE, mode),
+                                 words[1]));
+       }
+    }
+  else if (src_code == REG && dest_code == MEM)
+    {
+      rtx addr = XEXP (dest, 0);
+      rtx src0;
+      rtx src1;
+
+      if (GET_CODE (addr) != REG)
+       abort ();
+      
+      src0 = operand_subword (src, 0, TRUE, mode);
+      src1 = operand_subword (src, 1, TRUE, mode);
+      
+      emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, addr), src0));
+
+      if (REGNO (addr) == STACK_POINTER_REGNUM)
+       emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (stack_pointer_rtx, UNITS_PER_WORD)), src1));
+      else if (REGNO (addr) == FRAME_POINTER_REGNUM)
+       emit_insn (gen_rtx_SET (VOIDmode, change_address (dest, SImode, plus_constant (frame_pointer_rtx, UNITS_PER_WORD)), src1));
+      else
+       {
+         rtx new_mem;
+         
+         /* 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);
+         MEM_COPY_ATTRIBUTES (new_mem, dest);
+         
+         emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1));
+         emit_insn (gen_movsi_pop (src0));
+       }
+    }
+  else
+    /* This should have been prevented by the contraints on movdi_insn.  */
+    abort ();
+  
+  val = gen_sequence ();
+  end_sequence ();
+
+  return val;
+}
+
+/*}}}*/
 
 /* Local Variables: */
 /* folded-file: t   */
index 4d934ba..2bd1b6f 100644 (file)
@@ -84,7 +84,7 @@ extern int target_flags;
   { "small-model",      TARGET_SMALL_MODEL_MASK, "Assume small address space" }, \
   { "no-small-model", - TARGET_SMALL_MODEL_MASK, "" },                          \
   { "no-lsim",          0, "" },                                                \
-  { "",                 TARGET_DEFAULT }                                        \
+  { "",                 TARGET_DEFAULT, "" }                                    \
 }
 
 #define TARGET_VERSION fprintf (stderr, " (fr30)");
@@ -889,9 +889,10 @@ enum reg_class
      into the stack)
    - if the type is a structure or union. */
 
-#define MUST_PASS_IN_STACK(MODE,TYPE)                          \
+#define MUST_PASS_IN_STACK(MODE, TYPE)                         \
    (((MODE) == BLKmode)                                                \
-    || ((TYPE) != 0                                            \
+    || ((TYPE) != NULL                                         \
+         && TYPE_SIZE (TYPE) != NULL                           \
          && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST       \
             || TREE_CODE (TYPE) == RECORD_TYPE                 \
             || TREE_CODE (TYPE) == UNION_TYPE                  \
@@ -1763,6 +1764,8 @@ extern struct rtx_def * fr30_compare_op1;
   { "call_operand",            { MEM }},               \
   { "fp_displacement_operand", { CONST_INT }},         \
   { "sp_displacement_operand", { CONST_INT }},         \
+  { "di_operand",              { CONST_INT, CONST_DOUBLE, REG, MEM }}, \
+  { "nonimmediate_di_operand", { REG, MEM }},          \
   { "add_immediate_operand",   { REG, CONST_INT }},
 
 /*}}}*/ \f
index 1b8d310..296cdb2 100644 (file)
 )
 
 ;;}}}
+;;{{{ 8 Byte Moves
+
+;; Note - the FR30 does not have an 8 byte load/store instruction
+;; but we have to support this pattern because some other patterns
+;; (eg muldisi2) can produce a DImode result.
+;; (This code is stolen from the M32R port.)
+
+(define_expand "movdi"
+  [(set (match_operand:DI 0 "general_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+  ""
+  "
+  /* Everything except mem = const or mem = mem can be done easily.  */
+  
+  if (GET_CODE (operands[0]) == MEM)
+    operands[1] = force_reg (DImode, operands[1]);
+  ")
+
+;; We use an insn and a split so that we can generate
+;; RTL rather than text from fr30_move_double().
+
+(define_insn "*movdi_insn"
+  [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,m,r")
+       (match_operand:DI 1 "di_operand"               "r,m,r,nF"))]
+  "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"
+  "#"
+  [(set_attr "length" "4,8,12,12")]
+)
+
+(define_split
+  [(set (match_operand:DI 0 "nonimmediate_di_operand" "")
+       (match_operand:DI 1 "di_operand" ""))]
+  "reload_completed"
+  [(match_dup 2)]
+  "operands[2] = fr30_move_double (operands);")
+
+;;}}}
 ;;{{{ Load & Store Multiple Registers 
 
 ;; The load multiple and store multiple patterns are implemented