OSDN Git Service

2007-02-18 David Edelsohn <edelsohn@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.md
index 04eab3a..54202e4 100644 (file)
@@ -1,6 +1,6 @@
 ;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler
 ;; Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
 ;; Free Software Foundation, Inc.
 ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 (define_mode_macro FP [(SF "TARGET_HARD_FLOAT")
   (DF "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)")
   (TF "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128")])
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128")])
 
 ; Various instructions that come in SI and DI forms.
 ; A generic w/d attribute, for things like cmpw/cmpd.
 
 (define_expand "ctz<mode>2"
   [(set (match_dup 2)
-       (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))
+       (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))
    (parallel [(set (match_dup 3) (and:GPR (match_dup 1)
                                          (match_dup 2)))
              (clobber (scratch:CC))])
    (set (match_dup 4) (clz:GPR (match_dup 3)))
-   (set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+   (set (match_operand:GPR 0 "gpc_reg_operand" "")
        (minus:GPR (match_dup 5) (match_dup 4)))]
   ""
   {
 
 (define_expand "ffs<mode>2"
   [(set (match_dup 2)
-       (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))
+       (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))
    (parallel [(set (match_dup 3) (and:GPR (match_dup 1)
                                          (match_dup 2)))
              (clobber (scratch:CC))])
    (set (match_dup 4) (clz:GPR (match_dup 3)))
-   (set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+   (set (match_operand:GPR 0 "gpc_reg_operand" "")
        (minus:GPR (match_dup 5) (match_dup 4)))]
   ""
   {
      operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode));
   })
 
-(define_expand "popcount<mode>2"
-  [(set (match_dup 2)
-       (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")]
-                    UNSPEC_POPCNTB))
-   (set (match_dup 3)
-       (mult:GPR (match_dup 2) (match_dup 4)))
-   (set (match_operand:GPR 0 "gpc_reg_operand" "=r")
-       (lshiftrt:GPR (match_dup 3) (match_dup 5)))]
-  "TARGET_POPCNTB"
-  {
-    operands[2] = gen_reg_rtx (<MODE>mode);
-    operands[3] = gen_reg_rtx (<MODE>mode);
-    operands[4] = force_reg (<MODE>mode,
-                            <MODE>mode == SImode
-                            ? GEN_INT (0x01010101)
-                            : GEN_INT ((HOST_WIDE_INT)
-                                       0x01010101 << 32 | 0x01010101));
-    operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - 8);
-  })
-
 (define_insn "popcntb<mode>2"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
         (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")]
   "TARGET_POPCNTB"
   "popcntb %0,%1")
 
+(define_expand "popcount<mode>2"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "")
+       (popcount:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))]
+  "TARGET_POPCNTB"
+  {
+    rs6000_emit_popcount (operands[0], operands[1]);
+    DONE;
+  })
+
+(define_expand "parity<mode>2"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "")
+       (parity:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))]
+  "TARGET_POPCNTB"
+  {
+    rs6000_emit_parity (operands[0], operands[1]);
+    DONE;
+  })
+
+(define_insn "bswapsi2"
+  [(set (match_operand:SI 0 "reg_or_mem_operand" "=r,Z,&r")
+       (bswap:SI (match_operand:SI 1 "reg_or_mem_operand" "Z,r,r")))]
+  ""
+  "@
+   {lbrx|lwbrx} %0,%y1
+   {stbrx|stwbrx} %1,%y0
+   #"
+  [(set_attr "length" "4,4,12")])
+
+(define_split
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (bswap:SI (match_operand:SI 1 "gpc_reg_operand" "")))]
+  "reload_completed"
+  [(set (match_dup 0)
+       (rotate:SI (match_dup 1) (const_int 8)))
+   (set (zero_extract:SI (match_dup 0)
+                        (const_int 8)
+                        (const_int 0))
+       (match_dup 1))
+   (set (zero_extract:SI (match_dup 0)
+                        (const_int 8)
+                        (const_int 16))
+       (rotate:SI (match_dup 1)
+                  (const_int 16)))]
+  "")
+
 (define_expand "mulsi3"
   [(use (match_operand:SI 0 "gpc_reg_operand" ""))
    (use (match_operand:SI 1 "gpc_reg_operand" ""))
              (clobber (match_dup 4))
              (clobber (match_dup 5))
              (clobber (match_dup 6))])]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
   "
 {
   if (TARGET_E500_DOUBLE)
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (truncate:SI
         (lshiftrt:DI (mult:DI (sign_extend:DI
-                               (match_operand:SI 1 "gpc_reg_operand" "%r"))
+                               (match_operand:SI 1 "gpc_reg_operand" ""))
                               (sign_extend:DI
-                               (match_operand:SI 2 "gpc_reg_operand" "r")))
+                               (match_operand:SI 2 "gpc_reg_operand" "")))
                      (const_int 32))))]
   ""
   "
                                 operands[1], 0))
            {
              output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
-             output_asm_insn (\"{lx|lwzx} %L0,%1\", operands);
+             output_asm_insn (\"{l%X1|lwz%X1} %L0,%1\", operands);
              output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
-             return \"{lx|lwzx} %0,%1\";
+             return \"{l%X1|lwz%X1} %0,%1\";
            }
          else
            {
-             output_asm_insn (\"{lx|lwzx} %0,%1\", operands);
+             output_asm_insn (\"{l%X1|lwz%X1} %0,%1\", operands);
              output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
-             output_asm_insn (\"{lx|lwzx} %L0,%1\", operands);
+             output_asm_insn (\"{l%X1|lwz%X1} %L0,%1\", operands);
              output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
              return \"\";
            }
          rtx addreg;
 
          addreg = find_addr_reg (XEXP (operands[0], 0));
-         output_asm_insn (\"{stx|stwx} %1,%0\", operands);
+         output_asm_insn (\"{st%X0|stw%X0} %1,%0\", operands);
          output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
-         output_asm_insn (\"{stx|stwx} %L1,%0\", operands);
+         output_asm_insn (\"{st%X0|stw%X0} %L1,%0\", operands);
          output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
          return \"\";
        }
   [(set_attr "length" "8,8,8,20,20,16")])
 
 (define_insn_and_split "*movtf_softfloat"
-  [(set (match_operand:TF 0 "nonimmediate_operand" "=r,Y,r")
+  [(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=r,Y,r")
        (match_operand:TF 1 "input_operand"         "YGHF,r,r"))]
   "!TARGET_IEEEQUAD
    && (TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_LONG_DOUBLE_128
   [(set_attr "length" "20,20,16")])
 
 (define_expand "extenddftf2"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "")
+       (float_extend:TF (match_operand:DF 1 "input_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  if (TARGET_E500_DOUBLE)
+    emit_insn (gen_spe_extenddftf2 (operands[0], operands[1]));
+  else
+    emit_insn (gen_extenddftf2_fprs (operands[0], operands[1]));
+  DONE;
+})
+
+(define_expand "extenddftf2_fprs"
   [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "")
                   (float_extend:TF (match_operand:DF 1 "input_operand" "")))
              (use (match_dup 2))])]
   [(set (match_operand:TF 0 "nonimmediate_operand" "")
        (float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
 {
   rtx tmp = gen_reg_rtx (DFmode);
   emit_insn (gen_extendsfdf2 (tmp, operands[1]));
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
   "")
 
 (define_insn_and_split "trunctfdf2_internal1"
   "fadd %0,%1,%L1"
   [(set_attr "type" "fp")])
 
-(define_insn_and_split "trunctfsf2"
+(define_expand "trunctfsf2"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "")
+       (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  if (TARGET_E500_DOUBLE)
+    emit_insn (gen_spe_trunctfsf2 (operands[0], operands[1]));
+  else
+    emit_insn (gen_trunctfsf2_fprs (operands[0], operands[1]));
+  DONE;
+})
+
+(define_insn_and_split "trunctfsf2_fprs"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "f")))
    (clobber (match_scratch:DF 2 "=f"))]
   [(set (match_operand:TF 0 "gpc_reg_operand" "")
         (float:TF (match_operand:SI 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
 {
   rtx tmp = gen_reg_rtx (DFmode);
   expand_float (tmp, operands[1], false);
    (set_attr "length" "20")])
 
 (define_expand "fix_trunctfsi2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && (TARGET_POWER2 || TARGET_POWERPC)
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  if (TARGET_E500_DOUBLE)
+    emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1]));
+  else
+    emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1]));
+  DONE;
+})
+
+(define_expand "fix_trunctfsi2_fprs"
   [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
                   (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))
              (clobber (match_dup 2))
   DONE;
 })
 
-(define_insn "negtf2"
+(define_expand "negtf2"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "")
+       (neg:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+  "")
+
+(define_insn "negtf2_internal"
   [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
        (neg:TF (match_operand:TF 1 "gpc_reg_operand" "f")))]
   "!TARGET_IEEEQUAD
    (set_attr "length" "8")])
 
 (define_expand "abstf2"
-  [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
-       (abs:TF (match_operand:TF 1 "gpc_reg_operand" "f")))]
+  [(set (match_operand:TF 0 "gpc_reg_operand" "")
+       (abs:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
   "
 {
   rtx label = gen_label_rtx ();
-  emit_insn (gen_abstf2_internal (operands[0], operands[1], label));
+  if (TARGET_E500_DOUBLE)
+    {
+      if (flag_unsafe_math_optimizations)
+       emit_insn (gen_spe_abstf2_tst (operands[0], operands[1], label));
+      else
+       emit_insn (gen_spe_abstf2_cmp (operands[0], operands[1], label));
+    }
+  else
+    emit_insn (gen_abstf2_internal (operands[0], operands[1], label));
   emit_label (label);
   DONE;
 }")
 
 (define_expand "abstf2_internal"
-  [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
-       (match_operand:TF 1 "gpc_reg_operand" "f"))
+  [(set (match_operand:TF 0 "gpc_reg_operand" "")
+       (match_operand:TF 1 "gpc_reg_operand" ""))
    (set (match_dup 3) (match_dup 5))
    (set (match_dup 5) (abs:DF (match_dup 5)))
    (set (match_dup 4) (compare:CCFP (match_dup 3) (match_dup 5)))
 ; List r->r after r->"o<>", otherwise reload will try to reload a
 ; non-offsettable address by using r->r which won't make progress.
 (define_insn "*movdi_internal32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,r,r,*f,*f,m,r")
+  [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*f,*f,m,r")
        (match_operand:DI 1 "input_operand" "r,r,m,f,m,f,IJKnGHF"))]
   "! TARGET_POWERPC64
    && (gpc_reg_operand (operands[0], DImode)
 }")
 
 (define_split
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
+  [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "")
         (match_operand:DI 1 "input_operand" ""))]
   "reload_completed && !TARGET_POWERPC64
    && gpr_or_gpr_p (operands[0], operands[1])"
 ;; We move the back-chain and decrement the stack pointer.
 
 (define_expand "allocate_stack"
-  [(set (match_operand 0 "gpc_reg_operand" "=r")
+  [(set (match_operand 0 "gpc_reg_operand" "")
        (minus (reg 1) (match_operand 1 "reg_or_short_operand" "")))
    (set (reg 1)
        (minus (reg 1) (match_dup 1)))]
 
 (define_expand "bunordered"
   [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)"
+  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
   "{ rs6000_emit_cbranch (UNORDERED, operands[0]); DONE; }")
 
 (define_expand "bordered"
   [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)"
+  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
   "{ rs6000_emit_cbranch (ORDERED, operands[0]); DONE; }")
 
 (define_expand "buneq"
 
 (define_expand "sunordered"
   [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)"
+  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
   "{ rs6000_emit_sCOND (UNORDERED, operands[0]); DONE; }")
 
 (define_expand "sordered"
   [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)"
+  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
   "{ rs6000_emit_sCOND (ORDERED, operands[0]); DONE; }")
 
 (define_expand "suneq"
 
 (define_expand "tablejumpdi"
   [(set (match_dup 4)
-        (sign_extend:DI (match_operand:SI 0 "lwa_operand" "rm")))
+        (sign_extend:DI (match_operand:SI 0 "lwa_operand" "")))
    (set (match_dup 3)
        (plus:DI (match_dup 4)
                 (match_dup 2)))
 ; faster; for instance, on the 601 and 750.
 
 (define_expand "movsi_to_cr_one"
-  [(set (match_operand:CC 0 "cc_reg_operand" "=y")
-        (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
+  [(set (match_operand:CC 0 "cc_reg_operand" "")
+        (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "")
                    (match_dup 2)] UNSPEC_MOVESI_TO_CR))]
   ""
   "operands[2] = GEN_INT (1 << (75 - REGNO (operands[0])));")