OSDN Git Service

More soft-float/powerpc patches.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.md
index 0c0b223..1b884de 100644 (file)
    (set (match_operand:DF 0 "gpc_reg_operand" "")
        (minus:DF (subreg:DF (match_dup 2) 0)
                  (match_dup 5)))]
-  "! TARGET_POWERPC64"
+  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "
 {
   operands[2] = gen_reg_rtx (DImode);
    (set (match_operand:DF 0 "gpc_reg_operand" "")
        (minus:DF (subreg:DF (match_dup 2) 0)
                  (match_dup 4)))]
-  "! TARGET_POWERPC64"
+  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "
 {
   operands[2] = gen_reg_rtx (DImode);
 (define_insn ""
   [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,o,!r,f,f,m")
        (match_operand:DF 1 "input_operand" "r,o,r,G,f,m,f"))]
-  "! TARGET_POWERPC64 && (register_operand (operands[0], DFmode)
-   || register_operand (operands[1], DFmode))"
+  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT
+   && (register_operand (operands[0], DFmode)
+       || register_operand (operands[1], DFmode))"
   "*
 {
   switch (which_alternative)
    (set_attr "length" "8,8,8,8,*,*,*")])
 
 (define_insn ""
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r")
+       (match_operand:DF 1 "input_operand" "r,o,r,G"))]
+  "! TARGET_POWERPC64 && TARGET_SOFT_FLOAT
+   && (register_operand (operands[0], DFmode)
+       || register_operand (operands[1], DFmode))"
+  "*
+{
+  switch (which_alternative)
+    {
+    case 0:
+      /* We normally copy the low-numbered register first.  However, if
+        the first register operand 0 is the same as the second register of
+        operand 1, we must copy in the opposite order.  */
+      if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+       return \"mr %L0,%L1\;mr %0,%1\";
+      else
+       return \"mr %0,%1\;mr %L0,%L1\";
+    case 1:
+      /* If the low-address word is used in the address, we must load it
+        last.  Otherwise, load it first.  Note that we cannot have
+        auto-increment in that case since the address register is known to be
+        dead.  */
+      if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+                            operands [1], 0))
+       return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
+      else
+       return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
+    case 2:
+      return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
+    case 3:
+      return \"#\";
+    }
+}"
+  [(set_attr "type" "*,load,*,*")
+   (set_attr "length" "8,8,8,8")])
+
+(define_insn ""
   [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,o,!r,f,f,m")
        (match_operand:DF 1 "input_operand" "r,o,r,G,f,m,f"))]
-  "TARGET_POWERPC64 && (register_operand (operands[0], DFmode)
-   || register_operand (operands[1], DFmode))"
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT
+   && (register_operand (operands[0], DFmode)
+       || register_operand (operands[1], DFmode))"
   "@
    mr %0,%1
    ld%U1%X1 %0,%1
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0"
   [(set_attr "type" "*,load,*,*,fp,fpload,*")])
+
+(define_insn ""
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r")
+       (match_operand:DF 1 "input_operand" "r,o,r,G"))]
+  "TARGET_POWERPC64 && TARGET_SOFT_FLOAT
+   && (register_operand (operands[0], DFmode)
+       || register_operand (operands[1], DFmode))"
+  "@
+   mr %0,%1
+   ld%U1%X1 %0,%1
+   sd%U0%X0 %1,%0
+   #"
+  [(set_attr "type" "*,load,*,*")])
 \f
 ;; Next come the multi-word integer load and store and the load and store
 ;; multiple insns.
   [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
        (match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
    (clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
-  "TARGET_MULTIPLE && ! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
-   || gpc_reg_operand (operands[1], TImode))"
+  "TARGET_MULTIPLE && TARGET_POWER && ! TARGET_POWERPC64
+   && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
   "*
 {
   switch (which_alternative)
     {
+    default:
+      abort ();
+
     case 0:
       return \"{stsi|stswi} %1,%P0,16\";
 
    (set_attr "length" "*,16,16,*,16")])
 
 (define_insn ""
+  [(set (match_operand:TI 0 "reg_or_mem_operand" "=m,????r,????r")
+       (match_operand:TI 1 "reg_or_mem_operand" "r,r,m"))
+   (clobber (match_scratch:SI 2 "=X,X,X"))]
+  "TARGET_MULTIPLE && !TARGET_POWER && ! TARGET_POWERPC64
+   && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
+  "*
+{
+  switch (which_alternative)
+    {
+    default:
+      abort ();
+
+    case 0:
+      return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
+
+    case 1:
+      /* Normally copy registers with lowest numbered register copied first.
+        But copy in the other order if the first register of the output
+        is the second, third, or fourth register in the input.  */
+      if (REGNO (operands[0]) >= REGNO (operands[1]) + 1
+         && REGNO (operands[0]) <= REGNO (operands[1]) + 3)
+       return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
+      else
+       return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
+    case 2:
+      /* If the address register is the same as the register for the lowest-
+        addressed word, load it last.  Similarly for the next two words.
+        Otherwise load lowest address to highest.  */
+      if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+                            operands[1], 0))
+       return \"{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %0,%1\";
+      else if (refers_to_regno_p (REGNO (operands[0]) + 1,
+                                 REGNO (operands[0]) + 2, operands[1], 0))
+       return \"{l|lwz} %0,%1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %L0,%L1\";
+      else if (refers_to_regno_p (REGNO (operands[0]) + 2,
+                                 REGNO (operands[0]) + 3, operands[1], 0))
+       return \"{l|lwz} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Z0,%Z1\;{l|lwz} %Y0,%Y1\";
+      else
+       return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\";
+    }
+}"
+  [(set_attr "type" "load,*,*")
+   (set_attr "length" "16,16,16")])
+
+(define_insn ""
   [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
        (match_operand:TI 1 "input_operand" "r,m,r"))]
   "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
                   [(set (match_operand:SI 1 "indirect_operand" "=Q")
                         (match_operand:SI 2 "gpc_reg_operand" "r"))
                    (clobber (match_scratch:SI 3 "=q"))])]
-  "TARGET_MULTIPLE && !TARGET_POWERPC"
+  "TARGET_MULTIPLE && TARGET_POWER"
   "{stsi|stswi} %2,%P1,%O0")
 
 (define_insn ""
                   [(set (match_operand:SI 1 "indirect_operand" "=Q")
                         (match_operand:SI 2 "gpc_reg_operand" "r"))
                    (clobber (match_scratch:SI 3 "X"))])]
-  "TARGET_MULTIPLE && TARGET_POWERPC"
+  "TARGET_MULTIPLE && !TARGET_POWER"
   "{stsi|stswi} %2,%P1,%O0")
 \f
 ;; Define insns that do load or store with update.  Some of these we can