OSDN Git Service

Fix typos in comments.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.md
index 23279e7..7e701db 100644 (file)
@@ -39,7 +39,7 @@
 ;; Processor type -- this attribute must exactly match the processor_type
 ;; enumeration in rs6000.h.
 
-(define_attr "cpu" "rios1,rios2,ppc601,ppc603,ppc604,ppc620"
+(define_attr "cpu" "rios1,rios2,ppc403,ppc601,ppc603,ppc604,ppc620"
   (const (symbol_ref "rs6000_cpu_attr")))
 
 ; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
@@ -59,7 +59,7 @@
 
 (define_function_unit "iu" 1 0
   (and (eq_attr "type" "load")
-       (eq_attr "cpu" "rios1,ppc601"))
+       (eq_attr "cpu" "rios1,ppc403,ppc601"))
   2 0)
 
 (define_function_unit "iu" 1 0
 
 (define_function_unit "iu" 1 0
   (and (eq_attr "type" "imul")
+       (eq_attr "cpu" "ppc403"))
+  4 4)
+
+(define_function_unit "iu" 1 0
+  (and (eq_attr "type" "imul")
        (eq_attr "cpu" "ppc601,ppc603"))
   5 5)
 
 
 (define_function_unit "iu" 1 0
   (and (eq_attr "type" "idiv")
+       (eq_attr "cpu" "ppc403"))
+  33 33)
+
+(define_function_unit "iu" 1 0
+  (and (eq_attr "type" "idiv")
        (eq_attr "cpu" "ppc601"))
   36 36)
 
 
 (define_function_unit "bpu" 1 0
   (and (eq_attr "type" "mtjmpr")
-       (eq_attr "cpu" "ppc601,ppc603,ppc604,ppc620"))
+       (eq_attr "cpu" "ppc403,ppc601,ppc603,ppc604,ppc620"))
   4 0)
 
 ; Floating Point Unit (RIOS1, PPC601, PPC603, PPC604).
 
 (define_expand "uminsi3"
   [(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
-                             (const_int -2147483648)))
+                             (match_dup 5)))
    (set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "")
-                             (const_int -2147483648)))
+                             (match_dup 5)))
    (set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4))
                                       (const_int 0)
                                       (minus:SI (match_dup 4) (match_dup 3))))
        (minus:SI (match_dup 2) (match_dup 3)))]
   "TARGET_POWER"
   "
-{ operands[3] = gen_reg_rtx (SImode);  operands[4] = gen_reg_rtx (SImode); }")
+{
+  operands[3] = gen_reg_rtx (SImode);
+  operands[4] = gen_reg_rtx (SImode);
+  operands[5] = GEN_INT (-2147483647 - 1);
+}")
 
 (define_expand "umaxsi3"
   [(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
-                             (const_int -2147483648)))
+                             (match_dup 5)))
    (set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "")
-                             (const_int -2147483648)))
+                             (match_dup 5)))
    (set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4))
                                       (const_int 0)
                                       (minus:SI (match_dup 4) (match_dup 3))))
        (plus:SI (match_dup 3) (match_dup 1)))]
   "TARGET_POWER"
   "
-{ operands[3] = gen_reg_rtx (SImode);  operands[4] = gen_reg_rtx (SImode); }")
+{
+  operands[3] = gen_reg_rtx (SImode);
+  operands[4] = gen_reg_rtx (SImode);
+  operands[5] = GEN_INT (-2147483647 - 1);
+}")
 
 (define_insn ""
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
 
 ;; We don't need abs with condition code because such comparisons should
 ;; never be done.
-(define_insn "abssi2"
+(define_expand "abssi2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (abs:SI (match_operand:SI 1 "gpc_reg_operand" "")))]
+  ""
+  "
+{
+  if (!TARGET_POWER)
+    {
+      emit_insn (gen_abssi2_nopower (operands[0], operands[1]));
+      DONE;
+    }
+}")
+
+(define_insn "abssi2_power"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
   "TARGET_POWER"
   "abs %0,%1")
 
+(define_insn "abssi2_nopower"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+       (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))
+   (clobber (match_scratch:SI 2 "=&r,&r"))]
+  "!TARGET_POWER"
+  "*
+{
+  return (TARGET_POWERPC)
+    ? \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;subf %0,%2,%0\"
+    : \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;{sf|subfc} %0,%2,%0\";
+}"
+  [(set_attr "length" "12")])
+
+(define_split
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+       (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))
+   (clobber (match_scratch:SI 2 "=&r,&r"))]
+  "!TARGET_POWER && reload_completed"
+  [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31)))
+   (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1)))
+   (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 0)))]
+  "")
+
 (define_insn ""
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r"))))]
   "TARGET_POWER"
   "nabs %0,%1")
 
+(define_insn ""
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+       (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))))
+   (clobber (match_scratch:SI 2 "=&r,&r"))]
+  "!TARGET_POWER"
+  "*
+{
+  return (TARGET_POWERPC)
+    ? \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;subf %0,%0,%2\"
+    : \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;{sf|subfc} %0,%0,%2\";
+}"
+  [(set_attr "length" "12")])
+
+(define_split
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+       (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))))
+   (clobber (match_scratch:SI 2 "=&r,&r"))]
+  "!TARGET_POWER && reload_completed"
+  [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31)))
+   (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1)))
+   (set (match_dup 0) (minus:SI (match_dup 0) (match_dup 2)))]
+  "")
+
 (define_insn "negsi2"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (neg:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
   [(set_attr "type" "compare")])
 
 (define_insn "ffssi2"
-  [(set (match_operand:SI 0 "register_operand" "=&r")
-       (ffs:SI (match_operand:SI 1 "register_operand" "r")))]
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
+       (ffs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
   ""
   "neg %0,%1\;and %0,%0,%1\;{cntlz|cntlzw} %0,%0\;{sfi|subfic} %0,%0,32"
   [(set_attr "length" "16")])
 
 ;; AIX architecture-independent common-mode multiply (DImode),
 ;; divide/modulus, and quotient subroutine calls.  Input operands in R3 and
-;; R4; results in R3 and somtimes R4; link register always clobbered by bla
+;; R4; results in R3 and sometimes R4; link register always clobbered by bla
 ;; instruction; R0 sometimes clobbered; also, MQ sometimes clobbered but
 ;; assumed unused if generating common-mode, so ignore.
 (define_insn "mulh_call"
   "maskir %0,%3,%2")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=r")
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))
                        (match_operand:SI 1 "gpc_reg_operand" "0"))
                (and:SI (match_operand:SI 3 "gpc_reg_operand" "r")
                 (and:SI (match_operand:SI 3 "gpc_reg_operand" "r")
                         (match_dup 2)))
         (const_int 0)))
-   (set (match_operand:SI 0 "register_operand" "=r")
+   (set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1))
                (and:SI (match_dup 3) (match_dup 2))))]
   "TARGET_POWER"
   return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
 }")
 
+(define_insn ""
+  [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+                        (match_operand:SI 1 "const_int_operand" "i")
+                        (match_operand:SI 2 "const_int_operand" "i"))
+       (ashift:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+                  (match_operand:SI 4 "const_int_operand" "i")))]
+  ""
+  "*
+{
+  int shift = INTVAL (operands[4]) & 31;
+  int start = INTVAL (operands[2]) & 31;
+  int size = INTVAL (operands[1]) & 31;
+
+  operands[4] = gen_rtx (CONST_INT, VOIDmode, (shift - start - size) & 31);
+  operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1);
+  return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
+}")
+
+(define_insn ""
+  [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+                        (match_operand:SI 1 "const_int_operand" "i")
+                        (match_operand:SI 2 "const_int_operand" "i"))
+       (ashiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+                    (match_operand:SI 4 "const_int_operand" "i")))]
+  ""
+  "*
+{
+  int shift = INTVAL (operands[4]) & 31;
+  int start = INTVAL (operands[2]) & 31;
+  int size = INTVAL (operands[1]) & 31;
+
+  operands[4] = gen_rtx (CONST_INT, VOIDmode, (32 - shift - start - size) & 31);
+  operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1);
+  return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
+}")
+
+(define_insn ""
+  [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+                        (match_operand:SI 1 "const_int_operand" "i")
+                        (match_operand:SI 2 "const_int_operand" "i"))
+       (lshiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+                    (match_operand:SI 4 "const_int_operand" "i")))]
+  ""
+  "*
+{
+  int shift = INTVAL (operands[4]) & 31;
+  int start = INTVAL (operands[2]) & 31;
+  int size = INTVAL (operands[1]) & 31;
+
+  operands[4] = gen_rtx (CONST_INT, VOIDmode, (32 - shift - start - size) & 31);
+  operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1);
+  return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
+}")
+
+(define_insn ""
+  [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+                        (match_operand:SI 1 "const_int_operand" "i")
+                        (match_operand:SI 2 "const_int_operand" "i"))
+       (zero_extract:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+                        (match_operand:SI 4 "const_int_operand" "i")
+                        (match_operand:SI 5 "const_int_operand" "i")))]
+  "INTVAL (operands[4]) >= INTVAL (operands[1])"
+  "*
+{
+  int extract_start = INTVAL (operands[5]) & 31;
+  int extract_size = INTVAL (operands[4]) & 31;
+  int insert_start = INTVAL (operands[2]) & 31;
+  int insert_size = INTVAL (operands[1]) & 31;
+
+/* Align extract field with insert field */
+  operands[5] = gen_rtx (CONST_INT, VOIDmode,
+                        (extract_start + extract_size - insert_start - insert_size) & 31);
+  operands[1] = gen_rtx (CONST_INT, VOIDmode, insert_start + insert_size - 1);
+  return \"{rlimi|rlwimi} %0,%3,%5,%h2,%h1\";
+}")
+
 (define_insn "extzv"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r")
                           (match_operand:SI 2 "const_int_operand" "i"))
                (match_operand:SI 3 "mask_operand" "L")))]
   "includes_lshift_p (operands[2], operands[3])"
-  "{rlinm|rlwinm} %0,%h1,%h2,%m3,%M3")
+  "{rlinm|rlwinm} %0,%1,%h2,%m3,%M3")
 
 (define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x")
         (const_int 0)))
    (clobber (match_scratch:SI 4 "=r"))]
   "includes_lshift_p (operands[2], operands[3])"
-  "{rlinm.|rlwinm.} %4,%h1,%h2,%m3,%M3"
+  "{rlinm.|rlwinm.} %4,%1,%h2,%m3,%M3"
   [(set_attr "type" "delayed_compare")])
 
 (define_insn ""
    (set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (and:SI (ashift:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
   "includes_lshift_p (operands[2], operands[3])"
-  "{rlinm.|rlwinm.} %0,%h1,%h2,%m3,%M3"
+  "{rlinm.|rlwinm.} %0,%1,%h2,%m3,%M3"
   [(set_attr "type" "delayed_compare")])
 
 ;; The AIX assembler mis-handles "sri x,x,0", so write that case as
 (define_insn "extendsfdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (float_extend:DF (match_operand:SF 1 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "*
 {
   if (REGNO (operands[0]) == REGNO (operands[1]))
 (define_insn "truncdfsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "frsp %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn "negsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (neg:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fneg %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn "abssf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fabs %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (neg:SF (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f"))))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fnabs %0,%1"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (plus:SF (match_operand:SF 1 "gpc_reg_operand" "")
                 (match_operand:SF 2 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "")
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                 (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fadds %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                 (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fa|fadd} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (minus:SF (match_operand:SF 1 "gpc_reg_operand" "")
                  (match_operand:SF 2 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "")
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
                  (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fsubs %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
                  (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fs|fsub} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (mult:SF (match_operand:SF 1 "gpc_reg_operand" "")
                 (match_operand:SF 2 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "")
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                 (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fmuls %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                 (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fm|fmul} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (div:SF (match_operand:SF 1 "gpc_reg_operand" "")
                (match_operand:SF 2 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "")
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
                (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fdivs %0,%1,%2"
   [(set_attr "type" "sdiv")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
                (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fd|fdiv} %0,%1,%2"
   [(set_attr "type" "sdiv")])
 
        (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                          (match_operand:SF 2 "gpc_reg_operand" "f"))
                 (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fmadds %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                          (match_operand:SF 2 "gpc_reg_operand" "f"))
                 (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fma|fmadd} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                           (match_operand:SF 2 "gpc_reg_operand" "f"))
                  (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fmsubs %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                           (match_operand:SF 2 "gpc_reg_operand" "f"))
                  (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fms|fmsub} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                                  (match_operand:SF 2 "gpc_reg_operand" "f"))
                         (match_operand:SF 3 "gpc_reg_operand" "f"))))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fnmadds %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                                  (match_operand:SF 2 "gpc_reg_operand" "f"))
                         (match_operand:SF 3 "gpc_reg_operand" "f"))))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fnma|fnmadd} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                                   (match_operand:SF 2 "gpc_reg_operand" "f"))
                          (match_operand:SF 3 "gpc_reg_operand" "f"))))]
-  "TARGET_POWERPC"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT"
   "fnmsubs %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                                   (match_operand:SF 2 "gpc_reg_operand" "f"))
                          (match_operand:SF 3 "gpc_reg_operand" "f"))))]
-  "! TARGET_POWERPC"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "{fnms|fnmsub} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
 (define_expand "sqrtsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "TARGET_PPC_GPOPT || TARGET_POWER2"
+  "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT"
   "")
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GPOPT"
+  "TARGET_PPC_GPOPT && TARGET_HARD_FLOAT"
   "fsqrts %0,%1"
   [(set_attr "type" "ssqrt")])
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
-  "TARGET_POWER2"
+  "TARGET_POWER2 && TARGET_HARD_FLOAT"
   "fsqrt %0,%1"
   [(set_attr "type" "dsqrt")])
 
-;; For SMIN, SMAX, UMIN, and UMAX, we use DEFINE_EXPAND's that involve a fsel
-;; instruction and some auxiliary computations.  Then we just have a single
-;; DEFINE_INSN for fsel and the define_splits to make them if made by
+;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
+;; fsel instruction and some auxiliary computations.  Then we just have a
+;; single DEFINE_INSN for fsel and the define_splits to make them if made by
 ;; combine.
 (define_expand "maxsf3"
   [(set (match_dup 3)
                             (const_int 0))
                         (match_dup 1)
                         (match_dup 2)))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   "
 { operands[3] = gen_reg_rtx (SFmode); }")
 
        (smax:SF (match_operand:SF 1 "gpc_reg_operand" "")
                 (match_operand:SF 2 "gpc_reg_operand" "")))
    (clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   [(set (match_dup 3)
        (minus:SF (match_dup 1) (match_dup 2)))
    (set (match_dup 0)
                             (const_int 0))
                         (match_dup 1)
                         (match_dup 2)))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   "
 { operands[3] = gen_reg_rtx (SFmode); }")
 
        (smin:SF (match_operand:SF 1 "gpc_reg_operand" "")
                 (match_operand:SF 2 "gpc_reg_operand" "")))
    (clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   [(set (match_dup 3)
        (minus:SF (match_dup 2) (match_dup 1)))
    (set (match_dup 0)
                         (match_dup 2)))]
   "")
 
-(define_insn ""
+(define_expand "movsfcc"
+   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+        (if_then_else:SF (match_operand 1 "comparison_operator" "")
+                         (match_operand:SF 2 "gpc_reg_operand" "f")
+                         (match_operand:SF 3 "gpc_reg_operand" "f")))]
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+  "
+{
+  rtx temp, op0, op1;
+  enum rtx_code code = GET_CODE (operands[1]);
+  if (! rs6000_compare_fp_p)
+    FAIL;
+  switch (code)
+    {
+    case GE: case EQ: case NE:
+      op0 = rs6000_compare_op0;
+      op1 = rs6000_compare_op1;
+      break;
+    case GT:
+      op0 = rs6000_compare_op1;
+      op1 = rs6000_compare_op0;
+      temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+      break;
+    case LE:
+      op0 = rs6000_compare_op1;
+      op1 = rs6000_compare_op0;
+      break;
+    case LT:
+      op0 = rs6000_compare_op0;
+      op1 = rs6000_compare_op1;
+      temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+      break;
+    default:
+      FAIL;
+    }
+  if (GET_MODE (rs6000_compare_op0) == DFmode)
+    {
+      temp = gen_reg_rtx (DFmode);
+      emit_insn (gen_subdf3 (temp, op0, op1));
+      emit_insn (gen_fseldfsf4 (operands[0], temp, operands[2], operands[3]));
+      if (code == EQ)
+       {
+         emit_insn (gen_negdf2 (temp, temp));
+         emit_insn (gen_fseldfsf4 (operands[0], temp, operands[0], operands[3]));
+       }
+      if (code == NE)
+       {
+         emit_insn (gen_negdf2 (temp, temp));
+         emit_insn (gen_fseldfsf4 (operands[0], temp, operands[3], operands[0]));
+       }
+    }
+  else
+    {
+      temp = gen_reg_rtx (SFmode);
+      emit_insn (gen_subsf3 (temp, op0, op1));
+      emit_insn (gen_fselsfsf4 (operands[0], temp, operands[2], operands[3]));
+      if (code == EQ)
+       {
+         emit_insn (gen_negsf2 (temp, temp));
+         emit_insn (gen_fselsfsf4 (operands[0], temp, operands[0], operands[3]));
+       }
+      if (code == NE)
+       {
+         emit_insn (gen_negsf2 (temp, temp));
+         emit_insn (gen_fselsfsf4 (operands[0], temp, operands[3], operands[0]));
+       }
+    }
+  DONE;
+}")
+
+(define_insn "fselsfsf4"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
                             (const_int 0))
                         (match_operand:SF 2 "gpc_reg_operand" "f")
                         (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+  "fsel %0,%1,%2,%3"
+  [(set_attr "type" "fp")])
+
+(define_insn "fseldfsf4"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+       (if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
+                            (const_int 0))
+                        (match_operand:SF 2 "gpc_reg_operand" "f")
+                        (match_operand:SF 3 "gpc_reg_operand" "f")))]
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   "fsel %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
 (define_insn "negdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (neg:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fneg %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn "absdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fabs %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn ""
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (neg:DF (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f"))))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fnabs %0,%1"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (plus:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
                 (match_operand:DF 2 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fa|fadd} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (minus:DF (match_operand:DF 1 "gpc_reg_operand" "f")
                  (match_operand:DF 2 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fs|fsub} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
                 (match_operand:DF 2 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fm|fmul} %0,%1,%2"
   [(set_attr "type" "dmul")])
 
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (div:DF (match_operand:DF 1 "gpc_reg_operand" "f")
                (match_operand:DF 2 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fd|fdiv} %0,%1,%2"
   [(set_attr "type" "ddiv")])
 
        (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
                          (match_operand:DF 2 "gpc_reg_operand" "f"))
                 (match_operand:DF 3 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fma|fmadd} %0,%1,%2,%3"
   [(set_attr "type" "dmul")])
 
        (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
                           (match_operand:DF 2 "gpc_reg_operand" "f"))
                  (match_operand:DF 3 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fms|fmsub} %0,%1,%2,%3"
   [(set_attr "type" "dmul")])
 
        (neg:DF (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
                                  (match_operand:DF 2 "gpc_reg_operand" "f"))
                         (match_operand:DF 3 "gpc_reg_operand" "f"))))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fnma|fnmadd} %0,%1,%2,%3"
   [(set_attr "type" "dmul")])
 
        (neg:DF (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
                                   (match_operand:DF 2 "gpc_reg_operand" "f"))
                          (match_operand:DF 3 "gpc_reg_operand" "f"))))]
-  ""
+  "TARGET_HARD_FLOAT"
   "{fnms|fnmsub} %0,%1,%2,%3"
   [(set_attr "type" "dmul")])
 
 (define_insn "sqrtdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GPOPT || TARGET_POWER2"
+  "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT"
   "fsqrt %0,%1"
   [(set_attr "type" "dsqrt")])
 
-;; For SMIN, SMAX, UMIN, and UMAX, we use DEFINE_EXPAND's that involve a fsel
-;; instruction and some auxiliary computations.  Then we just have a single
-;; DEFINE_INSN for fsel and the define_splits to make them if made by
+;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
+;; fsel instruction and some auxiliary computations.  Then we just have a
+;; single DEFINE_INSN for fsel and the define_splits to make them if made by
 ;; combine.
 
 (define_expand "maxdf3"
                             (const_int 0))
                         (match_dup 1)
                         (match_dup 2)))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   "
 { operands[3] = gen_reg_rtx (DFmode); }")
 
        (smax:DF (match_operand:DF 1 "gpc_reg_operand" "")
                 (match_operand:DF 2 "gpc_reg_operand" "")))
    (clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   [(set (match_dup 3)
        (minus:DF (match_dup 1) (match_dup 2)))
    (set (match_dup 0)
                             (const_int 0))
                         (match_dup 1)
                         (match_dup 2)))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   "
 { operands[3] = gen_reg_rtx (DFmode); }")
 
        (smin:DF (match_operand:DF 1 "gpc_reg_operand" "")
                 (match_operand:DF 2 "gpc_reg_operand" "")))
    (clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
-  "TARGET_PPC_GFXOPT"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
   [(set (match_dup 3)
        (minus:DF (match_dup 2) (match_dup 1)))
    (set (match_dup 0)
                         (match_dup 2)))]
   "")
 
-(define_insn ""
+(define_expand "movdfcc"
+   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+        (if_then_else:DF (match_operand 1 "comparison_operator" "")
+                         (match_operand:DF 2 "gpc_reg_operand" "f")
+                         (match_operand:DF 3 "gpc_reg_operand" "f")))]
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+  "
+{
+  rtx temp, op0, op1;
+  enum rtx_code code = GET_CODE (operands[1]);
+  if (! rs6000_compare_fp_p)
+    FAIL;
+  switch (code)
+    {
+    case GE: case EQ: case NE:
+      op0 = rs6000_compare_op0;
+      op1 = rs6000_compare_op1;
+      break;
+    case GT:
+      op0 = rs6000_compare_op1;
+      op1 = rs6000_compare_op0;
+      temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+      break;
+    case LE:
+      op0 = rs6000_compare_op1;
+      op1 = rs6000_compare_op0;
+      break;
+    case LT:
+      op0 = rs6000_compare_op0;
+      op1 = rs6000_compare_op1;
+      temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+      break;
+    default:
+      FAIL;
+    }
+  if (GET_MODE (rs6000_compare_op0) == DFmode)
+    {
+      temp = gen_reg_rtx (DFmode);
+      emit_insn (gen_subdf3 (temp, op0, op1));
+      emit_insn (gen_fseldfdf4 (operands[0], temp, operands[2], operands[3]));
+      if (code == EQ)
+       {
+         emit_insn (gen_negdf2 (temp, temp));
+         emit_insn (gen_fseldfdf4 (operands[0], temp, operands[0], operands[3]));
+       }
+      if (code == NE)
+       {
+         emit_insn (gen_negdf2 (temp, temp));
+         emit_insn (gen_fseldfdf4 (operands[0], temp, operands[3], operands[0]));
+       }
+    }
+  else
+    {
+      temp = gen_reg_rtx (SFmode);
+      emit_insn (gen_subsf3 (temp, op0, op1));
+      emit_insn (gen_fselsfdf4 (operands[0], temp, operands[2], operands[3]));
+      if (code == EQ)
+       {
+         emit_insn (gen_negsf2 (temp, temp));
+         emit_insn (gen_fselsfdf4 (operands[0], temp, operands[0], operands[3]));
+       }
+      if (code == NE)
+       {
+         emit_insn (gen_negsf2 (temp, temp));
+         emit_insn (gen_fselsfdf4 (operands[0], temp, operands[3], operands[0]));
+       }
+    }
+  DONE;
+}")
+
+(define_insn "fseldfdf4"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
                             (const_int 0))
                         (match_operand:DF 2 "gpc_reg_operand" "f")
                         (match_operand:DF 3 "gpc_reg_operand" "f")))]
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+  "fsel %0,%1,%2,%3"
+  [(set_attr "type" "fp")])
+
+(define_insn "fselsfdf4"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+       (if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
+                            (const_int 0))
+                        (match_operand:DF 2 "gpc_reg_operand" "f")
+                        (match_operand:DF 3 "gpc_reg_operand" "f")))]
   "TARGET_PPC_GFXOPT"
   "fsel %0,%1,%2,%3"
   [(set_attr "type" "fp")])
    (set (match_operand:DF 0 "gpc_reg_operand" "")
        (minus:DF (subreg:DF (match_dup 2) 0)
                  (match_dup 5)))]
-  "! TARGET_POWERPC64 && HOST_BITS_PER_INT == BITS_PER_WORD"
+  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "
 {
   operands[2] = gen_reg_rtx (DImode);
   operands[3] = gen_rtx (CONST_INT, VOIDmode, 0x80000000);
-  operands[4] = immed_double_const (0, 0x43300000, DImode);
-  operands[5] = force_reg (DFmode, immed_double_const (0x43300000,
-                                                      0x80000000, DFmode));
+  operands[4] = rs6000_immed_double_const (0, 0x43300000, DImode);
+  operands[5] = force_reg (DFmode, rs6000_immed_double_const (0x43300000,
+                                                             0x80000000,
+                                                             DFmode));
 }")
 
 (define_expand "floatunssidf2"
    (set (match_operand:DF 0 "gpc_reg_operand" "")
        (minus:DF (subreg:DF (match_dup 2) 0)
                  (match_dup 4)))]
-  "! TARGET_POWERPC64 && HOST_BITS_PER_INT == BITS_PER_WORD"
+  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "
 {
   operands[2] = gen_reg_rtx (DImode);
-  operands[3] = immed_double_const (0, 0x43300000, DImode);
-  operands[4] = force_reg (DFmode, immed_double_const (0x43300000, 0, DFmode));
+  operands[3] = rs6000_immed_double_const (0, 0x43300000, DImode);
+  operands[4] = force_reg (DFmode, rs6000_immed_double_const (0x43300000, 0, DFmode));
 }")
 
 ;; For the above two cases, we always split.
        (plus:DI (zero_extend:DI
                  (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
                          (match_operand:SI 2 "logical_operand" "")))
-                (match_operand:DI 3 "immediate_operand" "")))]
-  "reload_completed && HOST_BITS_PER_INT == BITS_PER_WORD
-   && GET_CODE (operands[3]) == CONST_DOUBLE
-   && CONST_DOUBLE_LOW (operands[3]) == 0"
+                (match_operand:DI 3 "low_32_bit_operand" "")))]
+  "reload_completed"
   [(set (match_dup 6) (xor:SI (match_dup 1) (match_dup 2)))
    (set (match_dup 4) (match_dup 5))]
   "
        (plus:DI (zero_extend:DI
                  (xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r")
                          (match_operand:SI 2 "logical_operand" "rKJ")))
-                (match_operand:DI 3 "immediate_operand" "n")))]
-  "HOST_BITS_PER_INT == BITS_PER_WORD
-   && GET_CODE (operands[3]) == CONST_DOUBLE
-   && CONST_DOUBLE_LOW (operands[3]) == 0"
+                (match_operand:DI 3 "low_32_bit_operand" "n")))]
+  ""
   "#"
   [(set_attr "length" "8")])
   
 (define_split
   [(set (match_operand:DI 0 "gpc_reg_operand" "=")
        (plus:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
-                (match_operand:DI 2 "immediate_operand" "")))]
-  "reload_completed && HOST_BITS_PER_INT == BITS_PER_WORD
-   && GET_CODE (operands[2]) == CONST_DOUBLE
-   && CONST_DOUBLE_LOW (operands[2]) == 0"
+                (match_operand:DI 2 "low_32_bit_operand" "")))]
+  "reload_completed"
   [(set (match_dup 3) (match_dup 4))
    (set (match_dup 5) (match_dup 1))]
   "
 (define_insn ""
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
        (plus:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r"))
-                (match_operand:DI 2 "immediate_operand" "n")))]
-  "HOST_BITS_PER_INT == BITS_PER_WORD
-   && GET_CODE (operands[2]) == CONST_DOUBLE
-   && CONST_DOUBLE_LOW (operands[2]) == 0"
+                (match_operand:DI 2 "low_32_bit_operand" "n")))]
+  ""
   "#"
   [(set_attr "length" "8")])
 
 (define_expand "fix_truncdfsi2"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "
 {
   if (TARGET_POWER2 || TARGET_POWERPC)
   [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
        (sign_extend:DI
         (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
-  "TARGET_POWER2 || TARGET_POWERPC"
+  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT"
   "{fcirz|fctiwz} %0,%1"
   [(set_attr "type" "fp")])
 
 (define_expand "fixuns_truncdfsi2"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "! TARGET_POWER2 && ! TARGET_POWERPC"
+  "! TARGET_POWER2 && ! TARGET_POWERPC && TARGET_HARD_FLOAT"
   "
 {
   emit_insn (gen_trunc_call (operands[0], operands[1],
   [(parallel [(set (match_operand:SI 0 "" "")
                   (fix:SI (match_operand:DF 1 "" "")))
              (use (match_operand:SI 2 "" ""))])]
-  ""
+  "TARGET_HARD_FLOAT"
   "
 {
   rtx insns = gen_trunc_call_rtl (operands[0], operands[1], operands[2]);
              (clobber (scratch:SI))])
    (set (match_operand:SI 0 "gpc_reg_operand" "")
        (reg:SI 3))]
-  ""
+  "TARGET_HARD_FLOAT"
   "
 { 
   rs6000_trunc_used = 1;
 (define_insn "floatdidf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (float:DF (match_operand:DI 1 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "fcfid %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn "fix_truncdfdi2"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
        (fix:DI (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT"
   "fctidz %0,%1"
   [(set_attr "type" "fp")])
 \f
 ;; PowerPC64 DImode operations.
 
 (define_insn "ffsdi2"
-  [(set (match_operand:DI 0 "register_operand" "=&r")
-       (ffs:DI (match_operand:DI 1 "register_operand" "r")))]
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
+       (ffs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))]
   "TARGET_POWERPC64"
   "neg %0,%1\;and %0,%0,%1\;cntlzd %0,%0\;subfic %0,%0,64"
   [(set_attr "length" "16")])
   [(set_attr "type" "*,*,*,compare,*,*,load,*")
    (set_attr "length" "*,*,12,*,8,*,*,*")])
 \f
-;; For floating-point, we normally deal with the floating-point registers.
-;; The sole exception is that parameter passing can produce floating-point
-;; values in fixed-point registers.  Unless the value is a simple constant
-;; or already in memory, we deal with this by allocating memory and copying
-;; the value explicitly via that memory location.
+;; For floating-point, we normally deal with the floating-point registers
+;; unless -msoft-float is used.  The sole exception is that parameter passing
+;; can produce floating-point values in fixed-point registers.  Unless the
+;; value is a simple constant or already in memory, we deal with this by
+;; allocating memory and copying the value explicitly via that memory location.
 (define_expand "movsf"
   [(set (match_operand:SF 0 "nonimmediate_operand" "")
        (match_operand:SF 1 "any_operand" ""))]
       && REGNO (SUBREG_REG (operands[1])) < FIRST_PSEUDO_REGISTER)
     operands[1] = alter_subreg (operands[1]);
 
-  if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32)
+  if (TARGET_SOFT_FLOAT && GET_CODE (operands[0]) == MEM)
+    operands[1] = force_reg (SFmode, operands[1]);
+
+  else if (TARGET_HARD_FLOAT)
     {
-      /* If this is a store to memory or another integer register do the
-        move directly.  Otherwise store to a temporary stack slot and
-        load from there into a floating point register.  */
-
-      if (GET_CODE (operands[0]) == MEM
-         || (GET_CODE (operands[0]) == REG
-             && (REGNO (operands[0]) < 32
-                 || (reload_in_progress
-                     && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))))
-       {
-         emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
-                         operand_subword (operands[1], 0, 0, SFmode));
-         DONE;
-       }
-      else
+      if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32)
        {
-         rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
-
-         emit_move_insn (stack_slot, operands[1]);
-         emit_move_insn (operands[0], stack_slot);
-         DONE;
+         /* If this is a store to memory or another integer register do the
+            move directly.  Otherwise store to a temporary stack slot and
+            load from there into a floating point register.  */
+
+         if (GET_CODE (operands[0]) == MEM
+             || (GET_CODE (operands[0]) == REG
+                 && (REGNO (operands[0]) < 32
+                     || (reload_in_progress
+                         && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))))
+           {
+             emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
+                             operand_subword (operands[1], 0, 0, SFmode));
+             DONE;
+           }
+         else
+           {
+             rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
+
+             emit_move_insn (stack_slot, operands[1]);
+             emit_move_insn (operands[0], stack_slot);
+             DONE;
+           }
        }
-    }
 
-  if (GET_CODE (operands[0]) == MEM)
-    {
-      /* If operands[1] is a register, it may have double-precision data
-        in it, so truncate it to single precision.  We need not do
-        this for POWERPC.  */
-      if (! TARGET_POWERPC && GET_CODE (operands[1]) == REG)
+      if (GET_CODE (operands[0]) == MEM)
        {
-         rtx newreg = reload_in_progress ? operands[1] : gen_reg_rtx (SFmode);
-         emit_insn (gen_truncdfsf2 (newreg,
-                                    gen_rtx (SUBREG, DFmode, operands[1], 0)));
-         operands[1] = newreg;
+         /* If operands[1] is a register, it may have double-precision data
+            in it, so truncate it to single precision.  We need not do
+            this for POWERPC.  */
+         if (! TARGET_POWERPC && GET_CODE (operands[1]) == REG)
+           {
+             rtx newreg = reload_in_progress ? operands[1] : gen_reg_rtx (SFmode);
+             emit_insn (gen_truncdfsf2 (newreg,
+                                        gen_rtx (SUBREG, DFmode, operands[1], 0)));
+             operands[1] = newreg;
+           }
+
+         operands[1] = force_reg (SFmode, operands[1]);
        }
 
-      operands[1] = force_reg (SFmode, operands[1]);
-    }
-
-  if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) < 32)
-    {
-      if (GET_CODE (operands[1]) == MEM
+      if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) < 32)
+       {
+         if (GET_CODE (operands[1]) == MEM
 #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && ! defined(REAL_IS_NOT_DOUBLE)
-         || GET_CODE (operands[1]) == CONST_DOUBLE
+             || GET_CODE (operands[1]) == CONST_DOUBLE
 #endif
-         || (GET_CODE (operands[1]) == REG
-             && (REGNO (operands[1]) < 32
-                 || (reload_in_progress
-                     && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))))
-       {
-         emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
-                         operand_subword (operands[1], 0, 0, SFmode));
-         DONE;
-       }
-      else
-       {
-         rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
-
-         emit_move_insn (stack_slot, operands[1]);
-         emit_move_insn (operands[0], stack_slot);
-         DONE;
+             || (GET_CODE (operands[1]) == REG
+                 && (REGNO (operands[1]) < 32
+                     || (reload_in_progress
+                         && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))))
+           {
+             emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
+                             operand_subword (operands[1], 0, 0, SFmode));
+             DONE;
+           }
+         else
+           {
+             rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
+
+             emit_move_insn (stack_slot, operands[1]);
+             emit_move_insn (operands[0], stack_slot);
+             DONE;
+           }
        }
     }
 
 (define_insn ""
   [(set (match_operand:SF 0 "fp_reg_or_mem_operand" "=f,f,m")
        (match_operand:SF 1 "input_operand" "f,m,f"))]
-  "gpc_reg_operand (operands[0], SFmode)
-   || gpc_reg_operand (operands[1], SFmode)"
+  "(gpc_reg_operand (operands[0], SFmode)
+   || gpc_reg_operand (operands[1], SFmode)) && TARGET_HARD_FLOAT"
   "@
    fmr %0,%1
    lfs%U1%X1 %0,%1
    stfs%U0%X0 %1,%0"
   [(set_attr "type" "fp,fpload,*")])
+
+(define_insn ""
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
+       (match_operand:SF 1 "input_operand" "r,m,r,I,J,R"))]
+  "(gpc_reg_operand (operands[0], SFmode)
+   || gpc_reg_operand (operands[1], SFmode)) && TARGET_SOFT_FLOAT"
+  "@
+   mr %0,%1
+   {l%U1%X1|lwz%U1%X1} %0,%1
+   {st%U0%X0|stw%U0%X0} %1,%0
+   {lil|li} %0,%1
+   {liu|lis} %0,%u1
+   {cal|la} %0,%1(%*)"
+  [(set_attr "type" "*,load,*,*,*,*")])
+
 \f
 (define_expand "movdf"
   [(set (match_operand:DF 0 "nonimmediate_operand" "")
 (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.
   [(parallel [(set (match_operand:TI 0 "general_operand" "")
                   (match_operand:TI 1 "general_operand" ""))
              (clobber (scratch:SI))])]
-  "TARGET_POWER || TARGET_POWERPC64"
+  "TARGET_MULTIPLE || TARGET_POWERPC64"
   "
 {
   if (GET_CODE (operands[0]) == MEM)
   [(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_POWER && ! 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_POWER"
+  "TARGET_MULTIPLE && TARGET_POWER"
+  "{stsi|stswi} %2,%P1,%O0")
+
+(define_insn ""
+  [(match_parallel 0 "store_multiple_operation"
+                  [(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_POWER"
   "{stsi|stswi} %2,%P1,%O0")
 \f
 ;; Define insns that do load or store with update.  Some of these we can 
                         (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  ""
+  "TARGET_HARD_FLOAT"
   "@
    lfsux %3,%0,%2
    lfsu %3,%2(%0)"
        (match_operand:SF 3 "gpc_reg_operand" "f,f"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  ""
+  "TARGET_HARD_FLOAT"
   "@
    stfsux %3,%0,%2
    stfsu %3,%2(%0)")
                         (match_operand:SI 2 "reg_or_short_operand" "r,I"))))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  ""
+  "TARGET_HARD_FLOAT"
   "@
    lfdux %3,%0,%2
    lfdu %3,%2(%0)"
        (match_operand:DF 3 "gpc_reg_operand" "f,f"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  ""
+  "TARGET_HARD_FLOAT"
   "@
    stfdux %3,%0,%2
    stfdu %3,%2(%0)")
    (set (match_operand:DF 2 "gpc_reg_operand" "=f")
        (match_operand:DF 3 "memory_operand" ""))]
   "TARGET_POWER2
+   && TARGET_HARD_FLOAT
    && registers_ok_for_quad_peep (operands[0], operands[2])
    && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3])
    && addrs_ok_for_quad_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))"
    (set (match_operand:DF 2 "memory_operand" "")
        (match_operand:DF 3 "gpc_reg_operand" "f"))]
   "TARGET_POWER2
+   && TARGET_HARD_FLOAT
    && registers_ok_for_quad_peep (operands[1], operands[3])
    && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2])
    && addrs_ok_for_quad_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
   ""
   "*
 {
-  if (GET_CODE (operands[0]) == REG)
-    {
 #ifndef USING_SVR4_H
-      return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
-#else
-      return \"{brl|blrl}\";
-#endif
-    }
+  if (GET_CODE (operands[0]) == REG)
+    return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
 
   return \"bl %z0\;%.\";
+
+#else
+  if (GET_CODE (operands[0]) == REG)
+    return \"{brl|blrl}\";
+
+  return \"bl %z0\";
+#endif
 }"
   [(set_attr "length" "8")])
 
   ""
   "*
 {
-  if (GET_CODE (operands[1]) == REG)
-    {
 #ifndef USING_SVR4_H
-      return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
-#else
-      return \"{brl|blrl}\";
-#endif
-    }
+  if (GET_CODE (operands[1]) == REG)
+    return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
 
   return \"bl %z1\;%.\";
+
+#else
+  if (GET_CODE (operands[1]) == REG)
+    return \"{brl|blrl}\";
+
+  return \"bl %z1\";
+#endif
 }"
   [(set_attr "length" "8")])
 
 (define_expand "cmpsf"
   [(set (cc0) (compare (match_operand:SF 0 "gpc_reg_operand" "")
                       (match_operand:SF 1 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "
 {
   rs6000_compare_op0 = operands[0];
 (define_expand "cmpdf"
   [(set (cc0) (compare (match_operand:DF 0 "gpc_reg_operand" "")
                       (match_operand:DF 1 "gpc_reg_operand" "")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "
 {
   rs6000_compare_op0 = operands[0];
   [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
        (compare:CCFP (match_operand:SF 1 "gpc_reg_operand" "f")
                      (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fcmpu %0,%1,%2"
   [(set_attr "type" "fpcompare")])
 
   [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
        (compare:CCFP (match_operand:DF 1 "gpc_reg_operand" "f")
                      (match_operand:DF 2 "gpc_reg_operand" "f")))]
-  ""
+  "TARGET_HARD_FLOAT"
   "fcmpu %0,%1,%2"
   [(set_attr "type" "fpcompare")])
 \f
    {sfi|subfic} %0,%1,%2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0"
    [(set_attr "length" "12,8,12,12,12")])
 
+;; Simplify (ne X (const_int 0)) on the PowerPC.  No need to on the Power,
+;; since it nabs/sr is just as fast.
+(define_insn ""
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (lshiftrt:SI (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))
+                    (const_int 31)))
+   (clobber (match_scratch:SI 2 "=&r"))]
+  "!TARGET_POWER"
+  "{ai|addic} %2,%1,-1\;{sfe|subfe} %0,%2,%1"
+  [(set_attr "length" "8")])
+
 ;; This is what (plus (ne X (const_int 0)) Y) looks like.
 (define_insn ""
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")