i386-protos.h (split_xf, [...]): Remove.
authorJan Hubicka <hubicka@freesoft.cz>
Thu, 18 Nov 1999 19:10:44 +0000 (20:10 +0100)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 18 Nov 1999 19:10:44 +0000 (11:10 -0800)
        * i386-protos.h (split_xf, ix86_split_movdi): Remove.
        (ix86_split_long_move): Declare.
        * i386.c (split_xf, ix86_split_movdi): Remove.
        (ix86_split_to_parts, ix86_split_long_move): New.
        * i386.md (dimode move splitters): Use ix86_split_long_move.
        (dfmode move splitters): Likewise.
        (xfmode move splitters): Likewise.
        (movsf_1): Allow F->r.
        (movdf_1, movxf_1): Allow F->ro.

Co-Authored-By: Richard Henderson <rth@cygnus.com>
From-SVN: r30578

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

index f8fe6c575cd0e469f1553bb3026462338ab6abd3..66758cd51e3f210b7391a9fd99562fd61cd246cb 100644 (file)
@@ -1,3 +1,16 @@
+Thu Nov 18 11:10:03 1999  Jan Hubicka  <hubicka@freesoft.cz>
+                         Richard Henderson  <rth@cygnus.com>
+
+       * i386-protos.h (split_xf, ix86_split_movdi): Remove.
+       (ix86_split_long_move): Declare.
+       * i386.c (split_xf, ix86_split_movdi): Remove.
+       (ix86_split_to_parts, ix86_split_long_move): New.
+       * i386.md (dimode move splitters): Use ix86_split_long_move.
+       (dfmode move splitters): Likewise.
+       (xfmode move splitters): Likewise.
+       (movsf_1): Allow F->r.
+       (movdf_1, movxf_1): Allow F->ro.
+
 1999-11-17  Mark Mitchell  <mark@codesourcery.com>
 
        * except.h (struct eh_entry): Add goto_entry_p.
index 7468ce80c2aa278be42b2a88e26ff62de2ed6a3f..a8e16b5eaa89c47e5de5482cabe76f6befcc1b9b 100644 (file)
@@ -73,7 +73,6 @@ extern void print_operand PROTO((FILE*, rtx, int));
 extern void print_operand_address PROTO((FILE*, rtx));
 
 extern void split_di PROTO((rtx[], int, rtx[], rtx[]));
-extern void split_xf PROTO((rtx, rtx[3]));
 
 extern char *output_387_binary_op PROTO((rtx, rtx*));
 extern char *output_fix_trunc PROTO((rtx, rtx*));
@@ -92,7 +91,7 @@ extern void ix86_expand_branch PROTO((enum rtx_code, int, rtx));
 extern int ix86_expand_setcc PROTO((enum rtx_code, int, rtx));
 extern int ix86_expand_int_movcc PROTO((rtx[]));
 extern int ix86_expand_fp_movcc PROTO((rtx[]));
-extern int ix86_split_movdi PROTO((rtx[]));
+extern int ix86_split_long_move PROTO((rtx[]));
 extern void ix86_split_ashldi PROTO((rtx *, rtx));
 extern void ix86_split_ashrdi PROTO((rtx *, rtx));
 extern void ix86_split_lshrdi PROTO((rtx *, rtx));
index 92289705f11cae44e6c9719e22ec684d3165ceb1..c8e89954be84b4c35c7fe2ab791a11cbae0be9a3 100644 (file)
@@ -2996,26 +2996,6 @@ split_di (operands, num, lo_half, hi_half)
        abort();
     }
 }
-
-void
-split_xf (orig, out)
-     rtx orig;
-     rtx out[3];
-{
-  if (REG_P (orig))
-    {
-      int regno = REGNO (orig);
-      out[0] = gen_rtx_REG (SImode, regno);
-      out[1] = gen_rtx_REG (SImode, regno + 1);
-      out[2] = gen_rtx_REG (SImode, regno + 2);
-    }
-  else
-    {
-      out[0] = change_address (orig, SImode, NULL_RTX);
-      out[1] = adj_offsettable_operand (out[0], 4);
-      out[2] = adj_offsettable_operand (out[0], 8);
-    }
-}
 \f
 /* Output code to perform a 387 binary operation in INSN, one of PLUS,
    MINUS, MULT or DIV.  OPERANDS are the insn operands, where operands[3]
@@ -4643,27 +4623,211 @@ ix86_expand_fp_movcc (operands)
   return 1;
 }
 
-int
-ix86_split_movdi (operands)
-     rtx operands[];
+/* Split operands 0 and 1 into SImode parts.  Similar to split_di, but
+   works for floating pointer parameters and nonoffsetable memories.
+   For pushes, it returns just stack offsets; the values will be saved
+   in the right order.  Maximally three parts are generated.  */
+
+static void
+ix86_split_to_parts (operand, parts, mode)
+     rtx operand;
+     rtx *parts;
+     enum machine_mode mode;
 {
-  split_di (operands+0, 1, operands+2, operands+3);
-  split_di (operands+1, 1, operands+4, operands+5);
-  if (reg_overlap_mentioned_p (operands[2], operands[1]))
+  int size = GET_MODE_SIZE (mode) / 4;
+
+  if (size < 2 || size > 3)
+    abort ();
+
+  if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand))
     {
-      rtx tmp;
-      if (!reg_overlap_mentioned_p (operands[3], operands[4]))
+      /* The only non-offsetable memories we handle are pushes.  */
+      if (! push_operand (operand, VOIDmode))
+       abort ();
+
+      PUT_MODE (operand, SImode);
+      parts[0] = parts[1] = parts[2] = operand;
+    }
+  else
+    {
+      if (mode == DImode)
+       split_di (&operand, 1, &parts[0], &parts[1]);
+      else
        {
-         tmp = operands[2], operands[2] = operands[3], operands[3] = tmp;
-         tmp = operands[4], operands[4] = operands[5], operands[5] = tmp;
+         if (REG_P (operand))
+           {
+             if (!reload_completed)
+               abort ();
+             parts[0] = gen_rtx_REG (SImode, REGNO (operand) + 0);
+             parts[1] = gen_rtx_REG (SImode, REGNO (operand) + 1);
+             if (size == 3)
+               parts[2] = gen_rtx_REG (SImode, REGNO (operand) + 2);
+           }
+         else if (offsettable_memref_p (operand))
+           {
+             PUT_MODE (operand, SImode);
+             parts[0] = operand;
+             parts[1] = adj_offsettable_operand (operand, 4);
+             if (size == 3)
+               parts[2] = adj_offsettable_operand (operand, 8);
+           }
+         else if (GET_CODE (operand) == CONST_DOUBLE)
+           {
+             REAL_VALUE_TYPE r;
+             long l[3];
+
+             REAL_VALUE_FROM_CONST_DOUBLE (r, operand);
+             switch (mode)
+               {
+               case XFmode:
+                 REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
+                 parts[2] = GEN_INT (l[2]);
+                 break;
+               case DFmode:
+                 REAL_VALUE_TO_TARGET_DOUBLE (r, l);
+                 break;
+               default:
+                 abort ();
+               }
+             parts[1] = GEN_INT (l[1]);
+             parts[0] = GEN_INT (l[0]);
+           }
+         else
+           abort ();
        }
-      else
+    }
+
+  return;
+}
+
+/* Emit insns to perform a move or push of DI, DF, and XF values.
+   Return false when normal moves are needed; true when all required
+   insns have been emitted.  Operands 2-4 contain the input values
+   int the correct order; operands 5-7 contain the output values.  */
+
+int 
+ix86_split_long_move (operands1)
+     rtx operands1[];
+{
+  rtx part[2][3];
+  rtx operands[2];
+  int size = GET_MODE_SIZE (GET_MODE (operands1[0])) / 4;
+  int push = 0;
+  int collisions = 0;
+
+  /* Make our own copy to avoid clobbering the operands.  */
+  operands[0] = copy_rtx (operands1[0]);
+  operands[1] = copy_rtx (operands1[1]);
+
+  if (size < 2 || size > 3)
+    abort ();
+
+  /* The only non-offsettable memory we handle is push.  */
+  if (push_operand (operands[0], VOIDmode))
+    push = 1;
+  else if (GET_CODE (operands[0]) == MEM
+          && ! offsettable_memref_p (operands[0]))
+    abort ();
+
+  ix86_split_to_parts (operands[0], part[0], GET_MODE (operands1[0]));
+  ix86_split_to_parts (operands[1], part[1], GET_MODE (operands1[0]));
+
+  /* When emitting push, take care for source operands on the stack.  */
+  if (push && GET_CODE (operands[1]) == MEM
+      && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
+    {
+      if (size == 3)
+       part[1][1] = part[1][2];
+      part[1][0] = part[1][1];
+    }
+
+  /* We need to do copy in the right order in case an address register 
+     of the source overlaps the destination.  */
+  if (REG_P (part[0][0]) && GET_CODE (part[1][0]) == MEM)
+    {
+      if (reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0)))
+       collisions++;
+      if (reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
+       collisions++;
+      if (size == 3
+         && reg_overlap_mentioned_p (part[0][2], XEXP (part[1][0], 0)))
+       collisions++;
+
+      /* Collision in the middle part can be handled by reordering.  */
+      if (collisions == 1 && size == 3
+         && reg_overlap_mentioned_p (part[0][1], XEXP (part[1][0], 0)))
        {
-         emit_insn (gen_push (operands[4]));
-         emit_insn (gen_rtx_SET (VOIDmode, operands[3], operands[5]));
-         emit_insn (gen_popsi1 (operands[2]));
+         rtx tmp;
+         tmp = part[0][1]; part[0][1] = part[0][2]; part[0][2] = tmp;
+         tmp = part[1][1]; part[1][1] = part[1][2]; part[1][2] = tmp;
+       }
 
-         return 1; /* DONE */
+      /* If there are more collisions, we can't handle it by reordering.
+        Do an lea to the last part and use only one colliding move.  */
+      else if (collisions > 1)
+       {
+         collisions = 1;
+         emit_insn (gen_rtx_SET (VOIDmode, part[0][size - 1],
+                                 XEXP (part[1][0], 0)));
+         part[1][0] = change_address (part[1][0], SImode, part[0][size - 1]);
+         part[1][1] = adj_offsettable_operand (part[1][0], 4);
+         if (size == 3)
+           part[1][2] = adj_offsettable_operand (part[1][0], 8);
+       }
+    }
+
+  if (push)
+    {
+      if (size == 3)
+       emit_insn (gen_push (part[1][2]));
+      emit_insn (gen_push (part[1][1]));
+      emit_insn (gen_push (part[1][0]));
+      return 1;
+    }
+
+  /* Choose correct order to not overwrite the source before it is copied.  */
+  if ((REG_P (part[0][0])
+       && REG_P (part[1][1])
+       && (REGNO (part[0][0]) == REGNO (part[1][1])
+          || (size == 3
+              && REGNO (part[0][0]) == REGNO (part[1][2]))))
+      || (collisions > 0
+         && reg_overlap_mentioned_p (part[0][0], XEXP (part[1][0], 0))))
+    {
+      if (size == 3)
+       {
+         operands1[2] = part[0][2];
+         operands1[3] = part[0][1];
+         operands1[4] = part[0][0];
+         operands1[5] = part[1][2];
+         operands1[6] = part[1][1];
+         operands1[7] = part[1][0];
+       }
+      else
+       {
+         operands1[2] = part[0][1];
+         operands1[3] = part[0][0];
+         operands1[5] = part[1][1];
+         operands1[6] = part[1][0];
+       }
+    }
+  else
+    {
+      if (size == 3)
+       {
+         operands1[2] = part[0][0];
+         operands1[3] = part[0][1];
+         operands1[4] = part[0][2];
+         operands1[5] = part[1][0];
+         operands1[6] = part[1][1];
+         operands1[7] = part[1][2];
+       }
+      else
+       {
+         operands1[2] = part[0][0];
+         operands1[3] = part[0][1];
+         operands1[5] = part[1][0];
+         operands1[6] = part[1][1];
        }
     }
 
index 82553cf043d4e85c316a5747e45519a79037d117..eb082278d7e1ec306a6c7cdf1708bbb1dcd65c82 100644 (file)
 (define_split
   [(set (match_operand:DI 0 "push_operand" "")
         (match_operand:DI 1 "general_operand" ""))]
-  ""
-  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 3))
-   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))]
-  "
-{
-  split_di (operands+1, 1, operands+2, operands+3);
-  /* Compensate for the fact that we're changing stack offsets in
-     the middle of this operation.  */
-  if (reg_mentioned_p (stack_pointer_rtx, operands[2]))
-    operands[2] = adj_offsettable_operand (operands[2], 4);
-}")
+  "reload_completed"
+  [(const_int 0)]
+  "if (!ix86_split_long_move (operands)) abort (); DONE;")
 
 ;; %%% This multiword shite has got to go.
 (define_split
         (match_operand:DI 1 "general_operand" ""))
    (clobber (reg:CC 17))]
   "reload_completed"
-  [(parallel [(set (match_dup 2) (match_dup 4))
+  [(parallel [(set (match_dup 2) (match_dup 5))
              (clobber (reg:CC 17))])
-   (parallel [(set (match_dup 3) (match_dup 5))
+   (parallel [(set (match_dup 3) (match_dup 6))
              (clobber (reg:CC 17))])]
-  "if (ix86_split_movdi (operands)) DONE;")
+  "if (ix86_split_long_move (operands)) DONE;")
   
 (define_split
   [(set (match_operand:DI 0 "nonimmediate_operand" "")
         (match_operand:DI 1 "general_operand" ""))]
   "reload_completed"
-  [(set (match_dup 2) (match_dup 4))
-   (set (match_dup 3) (match_dup 5))]
-  "if (ix86_split_movdi (operands)) DONE;")
+  [(set (match_dup 2) (match_dup 5))
+   (set (match_dup 3) (match_dup 6))]
+  "if (ix86_split_long_move (operands)) DONE;")
   
 (define_expand "movsf"
   [(set (match_operand:SF 0 "general_operand" "")
 
 (define_insn "*movsf_1"
   [(set (match_operand:SF 0 "nonimmediate_operand" "=f,m,f,*r,m,*r")
-       (match_operand:SF 1 "general_operand" "fm,f,G,*rm,*r,G"))]
+       (match_operand:SF 1 "general_operand" "fm,f,G,*rm,F*r,GF"))]
   ""
   "*
 {
   [(set (match_operand:DF 0 "push_operand" "")
        (match_operand:DF 1 "general_operand" ""))]
   "reload_completed"
-  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
-   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]
-  "
-{
-  split_di (operands+1, 1, operands+0, operands+1);
-  /* Compensate for the fact that we're changing stack offsets in
-     the middle of this operation.  */
-  if (reg_mentioned_p (stack_pointer_rtx, operands[0]))
-    operands[0] = adj_offsettable_operand (operands[0], 4);
-}")
+  [(const_int 0)]
+  "if (!ix86_split_long_move (operands)) abort (); DONE;")
 
 (define_insn "*movdf_1"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*&r,m,*r")
-       (match_operand:DF 1 "general_operand" "fm,f,G,*rm,*r,G"))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*r,o")
+       (match_operand:DF 1 "general_operand" "fm,f,G,*roF,F*r"))]
   ""
   "*
 {
 
     case 3:
     case 4:
-    case 5:
       return \"#\";
 
     default:
       abort();
     }
 }"
-  [(set_attr "type" "fmov,fmov,fmov,multi,multi,multi")])
+  [(set_attr "type" "fmov,fmov,fmov,multi,multi")])
 
 (define_split
   [(set (match_operand:DF 0 "nonimmediate_operand" "")
    && ! (FP_REG_P (operands[1]) || 
         (GET_CODE (operands[1]) == SUBREG
          && FP_REG_P (SUBREG_REG (operands[1]))))"
-  [(set (match_dup 0) (match_dup 2))
-   (set (match_dup 1) (match_dup 3))]
-  "split_di (operands+1, 1, operands+2, operands+3);
-   split_di (operands+0, 1, operands+0, operands+1);")
+  [(set (match_dup 2) (match_dup 5))
+   (set (match_dup 3) (match_dup 6))]
+  "if (ix86_split_long_move (operands)) DONE;")
 
 (define_insn "swapdf"
   [(set (match_operand:DF 0 "register_operand" "+f")
   "ix86_expand_move (XFmode, operands); DONE;")
 
 (define_insn "*pushxf"
-  [(set (match_operand:XF 0 "push_operand" "=<")
-       (match_operand:XF 1 "register_operand" "f"))]
+  [(set (match_operand:XF 0 "push_operand" "=<,<")
+       (match_operand:XF 1 "register_operand" "f,oF*r"))]
   ""
   "*
 {
 }"
   [(set_attr "type" "multi")])
 
+(define_split
+  [(set (match_operand:XF 0 "push_operand" "")
+       (match_operand:XF 1 "general_operand" ""))]
+  "reload_completed
+   && (!REG_P (operands[1]) || !FP_REGNO_P (REGNO (operands[1])))"
+  [(const_int 0)]
+  "if (!ix86_split_long_move (operands)) abort (); DONE;")
+
 (define_split
   [(set (match_operand:XF 0 "push_operand" "")
        (match_operand:XF 1 "register_operand" ""))]
 }")
 
 (define_insn "*movxf_1"
-  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*&r,o")
-       (match_operand:XF 1 "general_operand" "fm,f,G,*ro,*r"))]
+  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o")
+       (match_operand:XF 1 "general_operand" "fm,f,G,*roF,*r"))]
   ""
   "*
 {
 
 (define_split
   [(set (match_operand:XF 0 "nonimmediate_operand" "")
-       (match_operand:XF 1 "nonimmediate_operand" ""))]
-  "(REG_P (operands[0]) && ! FP_REGNO_P (REGNO (operands[0])))
-   || (REG_P (operands[1]) && ! FP_REGNO_P (REGNO (operands[1])))"
-  [(set (match_dup 0) (match_dup 3))
-   (set (match_dup 1) (match_dup 4))
-   (set (match_dup 2) (match_dup 5))]
-  "split_xf (operands[1], &operands[3]);
-   split_xf (operands[0], &operands[0]);")
+       (match_operand:XF 1 "general_operand" ""))]
+  "reload_completed
+   && ((REG_P (operands[0]) && ! FP_REGNO_P (REGNO (operands[0])))
+        || (REG_P (operands[1]) && ! FP_REGNO_P (REGNO (operands[1]))))"
+  [(set (match_dup 2) (match_dup 5))
+   (set (match_dup 3) (match_dup 6))
+   (set (match_dup 4) (match_dup 7))]
+  "if (ix86_split_long_move (operands)) DONE;")
 
 (define_insn "swapxf"
   [(set (match_operand:XF 0 "register_operand" "+f")