OSDN Git Service

* config/rs6000/rs6000.c (create_TOC_reference): Wrap high part
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.md
index 5efde36..e70598d 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, 2007
+;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
 ;; Free Software Foundation, Inc.
 ;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
@@ -39,7 +39,7 @@
    (CR6_REGNO                  74)
    (CR7_REGNO                  75)
    (MAX_CR_REGNO               75)
-   (XER_REGNO                  76)
+   (CA_REGNO                   76)
    (FIRST_ALTIVEC_REGNO                77)
    (LAST_ALTIVEC_REGNO         108)
    (VRSAVE_REGNO               109)
 ;; UNSPEC usage
 ;;
 
-(define_constants
-  [(UNSPEC_FRSP                        0)      ; frsp for POWER machines
-   (UNSPEC_TIE                 5)      ; tie stack contents and stack pointer
-   (UNSPEC_TOCPTR              6)      ; address of a word pointing to the TOC
-   (UNSPEC_TOC                 7)      ; address of the TOC (more-or-less)
-   (UNSPEC_MOVSI_GOT           8)
-   (UNSPEC_MV_CR_OV            9)      ; move_from_CR_ov_bit
-   (UNSPEC_FCTIWZ              10)
-   (UNSPEC_FRIM                        11)
-   (UNSPEC_FRIN                        12)
-   (UNSPEC_FRIP                        13)
-   (UNSPEC_FRIZ                        14)
-   (UNSPEC_LD_MPIC             15)     ; load_macho_picbase
-   (UNSPEC_MPIC_CORRECT                16)     ; macho_correct_pic
-   (UNSPEC_TLSGD               17)
-   (UNSPEC_TLSLD               18)
-   (UNSPEC_MOVESI_FROM_CR      19)
-   (UNSPEC_MOVESI_TO_CR                20)
-   (UNSPEC_TLSDTPREL           21)
-   (UNSPEC_TLSDTPRELHA         22)
-   (UNSPEC_TLSDTPRELLO         23)
-   (UNSPEC_TLSGOTDTPREL                24)
-   (UNSPEC_TLSTPREL            25)
-   (UNSPEC_TLSTPRELHA          26)
-   (UNSPEC_TLSTPRELLO          27)
-   (UNSPEC_TLSGOTTPREL         28)
-   (UNSPEC_TLSTLS              29)
-   (UNSPEC_FIX_TRUNC_TF                30)     ; fadd, rounding towards zero
-   (UNSPEC_MV_CR_GT            31)     ; move_from_CR_gt_bit
-   (UNSPEC_STFIWX              32)
-   (UNSPEC_POPCNTB             33)
-   (UNSPEC_FRES                        34)
-   (UNSPEC_SP_SET              35)
-   (UNSPEC_SP_TEST             36)
-   (UNSPEC_SYNC                        37)
-   (UNSPEC_LWSYNC              38)
-   (UNSPEC_ISYNC               39)
-   (UNSPEC_SYNC_OP             40)
-   (UNSPEC_ATOMIC              41)
-   (UNSPEC_CMPXCHG             42)
-   (UNSPEC_XCHG                        43)
-   (UNSPEC_AND                 44)
-   (UNSPEC_DLMZB               45)
-   (UNSPEC_DLMZB_CR            46)
-   (UNSPEC_DLMZB_STRLEN                47)
-   (UNSPEC_RSQRT               48)
+(define_c_enum "unspec"
+  [UNSPEC_FRSP                 ; frsp for POWER machines
+   UNSPEC_PROBE_STACK          ; probe stack memory reference
+   UNSPEC_TIE                  ; tie stack contents and stack pointer
+   UNSPEC_TOCPTR               ; address of a word pointing to the TOC
+   UNSPEC_TOC                  ; address of the TOC (more-or-less)
+   UNSPEC_MOVSI_GOT
+   UNSPEC_MV_CR_OV             ; move_from_CR_ov_bit
+   UNSPEC_FCTIWZ
+   UNSPEC_FRIM
+   UNSPEC_FRIN
+   UNSPEC_FRIP
+   UNSPEC_FRIZ
+   UNSPEC_LD_MPIC              ; load_macho_picbase
+   UNSPEC_MPIC_CORRECT         ; macho_correct_pic
+   UNSPEC_TLSGD
+   UNSPEC_TLSLD
+   UNSPEC_MOVESI_FROM_CR
+   UNSPEC_MOVESI_TO_CR
+   UNSPEC_TLSDTPREL
+   UNSPEC_TLSDTPRELHA
+   UNSPEC_TLSDTPRELLO
+   UNSPEC_TLSGOTDTPREL
+   UNSPEC_TLSTPREL
+   UNSPEC_TLSTPRELHA
+   UNSPEC_TLSTPRELLO
+   UNSPEC_TLSGOTTPREL
+   UNSPEC_TLSTLS
+   UNSPEC_FIX_TRUNC_TF         ; fadd, rounding towards zero
+   UNSPEC_MV_CR_GT             ; move_from_CR_gt_bit
+   UNSPEC_STFIWX
+   UNSPEC_POPCNTB
+   UNSPEC_FRES
+   UNSPEC_SP_SET
+   UNSPEC_SP_TEST
+   UNSPEC_SYNC
+   UNSPEC_SYNC_OP
+   UNSPEC_ATOMIC
+   UNSPEC_CMPXCHG
+   UNSPEC_XCHG
+   UNSPEC_AND
+   UNSPEC_DLMZB
+   UNSPEC_DLMZB_CR
+   UNSPEC_DLMZB_STRLEN
+   UNSPEC_RSQRT
+   UNSPEC_TOCREL
+   UNSPEC_MACHOPIC_OFFSET
+   UNSPEC_BPERM
+   UNSPEC_COPYSIGN
+   UNSPEC_PARITY
+   UNSPEC_FCTIW
+   UNSPEC_FCTID
+   UNSPEC_LFIWAX
+   UNSPEC_LFIWZX
+   UNSPEC_FCTIWUZ
   ])
 
 ;;
 ;; UNSPEC_VOLATILE usage
 ;;
 
-(define_constants
-  [(UNSPECV_BLOCK              0)
-   (UNSPECV_LL                 1)      ; load-locked
-   (UNSPECV_SC                 2)      ; store-conditional
-   (UNSPECV_EH_RR              9)      ; eh_reg_restore
+(define_c_enum "unspecv"
+  [UNSPECV_BLOCK
+   UNSPECV_LL                  ; load-locked
+   UNSPECV_SC                  ; store-conditional
+   UNSPECV_PROBE_STACK_RANGE   ; probe range of stack addresses
+   UNSPECV_EH_RR               ; eh_reg_restore
+   UNSPECV_ISYNC               ; isync instruction
+   UNSPECV_LWSYNC              ; lwsync
   ])
+
 \f
 ;; Define an insn type attribute.  This is used in function unit delay
 ;; computations.
-(define_attr "type" "integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr"
+(define_attr "type" "integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr,isel"
   (const_string "integer"))
 
+;; Define floating point instruction sub-types for use with Xfpu.md
+(define_attr "fp_type" "fp_default,fp_addsub_s,fp_addsub_d,fp_mul_s,fp_mul_d,fp_div_s,fp_div_d,fp_maddsub_s,fp_maddsub_d,fp_sqrt_s,fp_sqrt_d" (const_string "fp_default"))
+
 ;; Length (in bytes).
 ; '(pc)' in the following doesn't include the instruction itself; it is
 ; calculated as if the instruction had zero size.
 ;; Processor type -- this attribute must exactly match the processor_type
 ;; enumeration in rs6000.h.
 
-(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,power4,power5,power6,cell"
+(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc476,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,ppce500mc64,power4,power5,power6,power7,cell,ppca2,titan"
   (const (symbol_ref "rs6000_cpu_attr")))
 
 
 ;; If this instruction is microcoded on the CELL processor
-; The default for load and stores is conditional
-; The default for load extended and the recorded instructions is always microcoded
+; The default for load extended, the recorded instructions and rotate/shifts by a variable is always microcoded
 (define_attr "cell_micro" "not,conditional,always"
-  (if_then_else (ior (ior (eq_attr "type" "load")
-                          (eq_attr "type" "store"))
-                     (ior (eq_attr "type" "fpload")
-                          (eq_attr "type" "fpstore")))
-               (const_string "conditional")
-                (if_then_else (ior (eq_attr "type" "load_ext")
-                                  (ior (eq_attr "type" "compare")
-                                       (eq_attr "type" "delayed_compare")))
-                             (const_string "always")
-                              (const_string "not"))))
-
+  (if_then_else (eq_attr "type" "compare,delayed_compare,imul_compare,lmul_compare,load_ext,load_ext_ux,var_shift_rotate,var_delayed_compare")
+               (const_string "always")
+               (const_string "not")))
 
 (automata_option "ndfa")
 
 (include "mpc.md")
 (include "40x.md")
 (include "440.md")
+(include "476.md")
 (include "603.md")
 (include "6xx.md")
 (include "7xx.md")
 (include "8540.md")
 (include "e300c2c3.md")
 (include "e500mc.md")
+(include "e500mc64.md")
 (include "power4.md")
 (include "power5.md")
 (include "power6.md")
+(include "power7.md")
 (include "cell.md")
+(include "xfpu.md")
+(include "a2.md")
+(include "titan.md")
 
 (include "predicates.md")
 (include "constraints.md")
 (define_mode_iterator SDI [SI DI])
 
 ; The size of a pointer.  Also, the size of the value that a record-condition
-; (one with a '.') will compare.
+; (one with a '.') will compare; and the size used for arithmetic carries.
 (define_mode_iterator P [(SI "TARGET_32BIT") (DI "TARGET_64BIT")])
 
 ; Any hardware-supported floating-point mode
-(define_mode_iterator FP [(SF "TARGET_HARD_FLOAT")
-  (DF "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)")
+(define_mode_iterator FP [
+  (SF "TARGET_HARD_FLOAT 
+   && ((TARGET_FPRS && TARGET_SINGLE_FLOAT) || TARGET_E500_SINGLE)")
+  (DF "TARGET_HARD_FLOAT 
+   && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)")
   (TF "!TARGET_IEEEQUAD
    && TARGET_HARD_FLOAT
    && (TARGET_FPRS || TARGET_E500_DOUBLE)
   (DD "TARGET_DFP")
   (TD "TARGET_DFP")])
 
+; Any fma capable floating-point mode.
+(define_mode_iterator FMA_F [
+  (SF "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT")
+  (DF "(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
+       || VECTOR_UNIT_VSX_P (DFmode)")
+  (V2SF "TARGET_PAIRED_FLOAT")
+  (V4SF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)")
+  (V2DF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V2DFmode)")
+  ])
+
+; These modes do not fit in integer registers in 32-bit mode.
+; but on e500v2, the gpr are 64 bit registers
+(define_mode_iterator DIFD [DI (DF "!TARGET_E500_DOUBLE") DD])
+
+; Iterator for reciprocal estimate instructions
+(define_mode_iterator RECIPF [SF DF V4SF V2DF])
+
+; Iterator for just SF/DF
+(define_mode_iterator SFDF [SF DF])
+
 ; Various instructions that come in SI and DI forms.
 ; A generic w/d attribute, for things like cmpw/cmpd.
 (define_mode_attr wd [(QI "b") (HI "h") (SI "w") (DI "d")])
 ; DImode bits
 (define_mode_attr dbits [(QI "56") (HI "48") (SI "32")])
 
+;; ISEL/ISEL64 target selection
+(define_mode_attr sel [(SI "") (DI "64")])
+
+;; Suffix for reload patterns
+(define_mode_attr ptrsize [(SI "32bit")
+                          (DI "64bit")])
+
+(define_mode_attr tptrsize [(SI "TARGET_32BIT")
+                           (DI "TARGET_64BIT")])
+
+(define_mode_attr mptrsize [(SI "si")
+                           (DI "di")])
+
+(define_mode_attr rreg [(SF   "f")
+                       (DF   "ws")
+                       (V4SF "wf")
+                       (V2DF "wd")])
+
+(define_mode_attr rreg2 [(SF   "f")
+                        (DF   "d")])
+
+(define_mode_attr SI_CONVERT_FP [(SF "TARGET_FCFIDS")
+                                (DF "TARGET_FCFID")])
+
+(define_mode_attr E500_CONVERT [(SF "!TARGET_FPRS")
+                               (DF "TARGET_E500_DOUBLE")])
+
+(define_mode_attr TARGET_FLOAT [(SF "TARGET_SINGLE_FLOAT")
+                               (DF "TARGET_DOUBLE_FLOAT")])
 \f
 ;; Start with fixed-point load and store insns.  Here we put only the more
 ;; complex forms.  Basic data transfer is done later.
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:DI 2 ""))]
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:DI 2 ""))]
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "")
 (define_insn ""
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
        (sign_extend:DI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && rs6000_gen_cell_microcode"
   "@
    lha%U1%X1 %0,%1
    extsh %0,%1"
   [(set_attr "type" "load_ext,exts")])
 
 (define_insn ""
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r")))]
+  "TARGET_POWERPC64 && !rs6000_gen_cell_microcode"
+  "extsh %0,%1"
+  [(set_attr "type" "exts")])
+
+(define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
        (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
                    (const_int 0)))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:DI 2 ""))]
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "")
 (define_insn ""
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
        (sign_extend:DI (match_operand:SI 1 "lwa_operand" "m,r")))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && rs6000_gen_cell_microcode"
   "@
    lwa%U1%X1 %0,%1
    extsw %0,%1"
   [(set_attr "type" "load_ext,exts")])
 
 (define_insn ""
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r")))]
+  "TARGET_POWERPC64 && !rs6000_gen_cell_microcode"
+  "extsw %0,%1"
+  [(set_attr "type" "exts")])
+
+(define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
        (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
                    (const_int 0)))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:DI 2 ""))]
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "")
   "@
    {andil.|andi.} %2,%1,0xff
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:SI 2 ""))]
   "@
    {andil.|andi.} %0,%1,0xff
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:SI 0 "gpc_reg_operand" "")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:SI 2 ""))]
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:SI 0 "gpc_reg_operand" "")
   "@
    {andil.|andi.} %2,%1,0xff
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:HI 2 ""))]
   "@
    {andil.|andi.} %0,%1,0xff
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:HI 0 "gpc_reg_operand" "")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:HI 2 ""))]
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:HI 0 "gpc_reg_operand" "")
   "@
    {andil.|andi.} %2,%1,0xffff
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:SI 2 ""))]
   "@
    {andil.|andi.} %0,%1,0xffff
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:SI 0 "gpc_reg_operand" "")
 (define_insn ""
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
        (sign_extend:SI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))]
-  ""
+  "rs6000_gen_cell_microcode"
   "@
    lha%U1%X1 %0,%1
    {exts|extsh} %0,%1"
   [(set_attr "type" "load_ext,exts")])
 
 (define_insn ""
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+        (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r")))]
+  "!rs6000_gen_cell_microcode"
+  "{exts|extsh} %0,%1"
+  [(set_attr "type" "exts")])
+
+(define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
        (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
                    (const_int 0)))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:SI 2 ""))]
   [(set_attr "type" "compare")
    (set_attr "length" "4,8")])
 \f
-;; IBM 405, 440 and 464 half-word multiplication operations.
+;; IBM 405, 440, 464 and 476 half-word multiplication operations.
 
 (define_insn "*macchwc"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x")
   "mullhwu %0, %1, %2"
   [(set_attr "type" "imul3")])
 \f
-;; IBM 405, 440 and 464 string-search dlmzb instruction support.
+;; IBM 405, 440, 464 and 476 string-search dlmzb instruction support.
 (define_insn "dlmzb"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x")
         (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
 })
 \f
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:SI 0 "gpc_reg_operand" "")
   "@
    nor. %2,%1,%1
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (not:P (match_operand:P 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (clobber (match_scratch:P 2 ""))]
   "@
    nor. %0,%1,%1
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (not:P (match_operand:P 1 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set (match_operand:P 0 "gpc_reg_operand" "")
   "TARGET_POWER"
   "abs %0,%1")
 
-(define_insn_and_split "abssi2_isel"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-        (abs:SI (match_operand:SI 1 "gpc_reg_operand" "b")))
-   (clobber (match_scratch:SI 2 "=&b"))
+(define_insn_and_split "abs<mode>2_isel"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+        (abs:GPR (match_operand:GPR 1 "gpc_reg_operand" "b")))
+   (clobber (match_scratch:GPR 2 "=&b"))
    (clobber (match_scratch:CC 3 "=y"))]
   "TARGET_ISEL"
   "#"
   "&& reload_completed"
-  [(set (match_dup 2) (neg:SI (match_dup 1)))
+  [(set (match_dup 2) (neg:GPR (match_dup 1)))
    (set (match_dup 3)
        (compare:CC (match_dup 1)
                    (const_int 0)))
    (set (match_dup 0)
-       (if_then_else:SI (ge (match_dup 3)
-                            (const_int 0))
-                        (match_dup 1)
-                        (match_dup 2)))]
+       (if_then_else:GPR (lt (match_dup 3)
+                             (const_int 0))
+                         (match_dup 2)
+                         (match_dup 1)))]
+  "")
+
+(define_insn_and_split "nabs<mode>2_isel"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+        (neg:GPR (abs:GPR (match_operand:GPR 1 "gpc_reg_operand" "b"))))
+   (clobber (match_scratch:GPR 2 "=&b"))
+   (clobber (match_scratch:CC 3 "=y"))]
+  "TARGET_ISEL"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (neg:GPR (match_dup 1)))
+   (set (match_dup 3)
+       (compare:CC (match_dup 1)
+                   (const_int 0)))
+   (set (match_dup 0)
+       (if_then_else:GPR (lt (match_dup 3)
+                             (const_int 0))
+                         (match_dup 1)
+                         (match_dup 2)))]
   "")
 
 (define_insn_and_split "abssi2_nopower"
   "TARGET_POPCNTB"
   "popcntb %0,%1")
 
+(define_insn "popcntd<mode>2"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+       (popcount:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
+  "TARGET_POPCNTD"
+  "popcnt<wd> %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"
+  "TARGET_POPCNTB || TARGET_POPCNTD"
   {
     rs6000_emit_popcount (operands[0], operands[1]);
     DONE;
   })
 
+(define_insn "parity<mode>2_cmpb"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+       (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")] UNSPEC_PARITY))]
+  "TARGET_CMPB && TARGET_POPCNTB"
+  "prty<wd> %0,%1")
+
 (define_expand "parity<mode>2"
   [(set (match_operand:GPR 0 "gpc_reg_operand" "")
        (parity:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))]
     DONE;
   })
 
-(define_insn "bswapsi2"
+;; Since the hardware zeros the upper part of the register, save generating the
+;; AND immediate if we are converting to unsigned
+(define_insn "*bswaphi2_extenddi"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (zero_extend:DI
+        (bswap:HI (match_operand:HI 1 "memory_operand" "Z"))))]
+  "TARGET_POWERPC64"
+  "lhbrx %0,%y1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")])
+
+(define_insn "*bswaphi2_extendsi"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (zero_extend:SI
+        (bswap:HI (match_operand:HI 1 "memory_operand" "Z"))))]
+  "TARGET_POWERPC"
+  "lhbrx %0,%y1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")])
+
+(define_expand "bswaphi2"
+  [(parallel [(set (match_operand:HI 0 "reg_or_mem_operand" "")
+                  (bswap:HI
+                   (match_operand:HI 1 "reg_or_mem_operand" "")))
+             (clobber (match_scratch:SI 2 ""))])]
+  ""
+{
+  if (!REG_P (operands[0]) && !REG_P (operands[1]))
+    operands[1] = force_reg (HImode, operands[1]);
+})
+
+(define_insn "bswaphi2_internal"
+  [(set (match_operand:HI 0 "reg_or_mem_operand" "=r,Z,&r")
+       (bswap:HI
+        (match_operand:HI 1 "reg_or_mem_operand" "Z,r,r")))
+   (clobber (match_scratch:SI 2 "=X,X,&r"))]
+  "TARGET_POWERPC"
+  "@
+   lhbrx %0,%y1
+   sthbrx %1,%y0
+   #"
+  [(set_attr "length" "4,4,12")
+   (set_attr "type" "load,store,*")])
+
+(define_split
+  [(set (match_operand:HI 0 "gpc_reg_operand" "")
+       (bswap:HI (match_operand:HI 1 "gpc_reg_operand" "")))
+   (clobber (match_operand:SI 2 "gpc_reg_operand" ""))]
+  "TARGET_POWERPC && reload_completed"
+  [(set (match_dup 3)
+       (zero_extract:SI (match_dup 4)
+                        (const_int 8)
+                        (const_int 16)))
+   (set (match_dup 2)
+       (and:SI (ashift:SI (match_dup 4)
+                          (const_int 8))
+               (const_int 65280)))             ;; 0xff00
+   (set (match_dup 3)
+       (ior:SI (match_dup 3)
+               (match_dup 2)))]
+  "
+{
+  operands[3] = simplify_gen_subreg (SImode, operands[0], HImode, 0);
+  operands[4] = simplify_gen_subreg (SImode, operands[1], HImode, 0);
+}")
+
+(define_insn "*bswapsi2_extenddi"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (zero_extend:DI
+        (bswap:SI (match_operand:SI 1 "memory_operand" "Z"))))]
+  "TARGET_POWERPC64"
+  "lwbrx %0,%y1"
+  [(set_attr "length" "4")
+   (set_attr "type" "load")])
+
+(define_expand "bswapsi2"
+  [(set (match_operand:SI 0 "reg_or_mem_operand" "")
+       (bswap:SI
+        (match_operand:SI 1 "reg_or_mem_operand" "")))]
+  ""
+{
+  if (!REG_P (operands[0]) && !REG_P (operands[1]))
+    operands[1] = force_reg (SImode, operands[1]);
+})
+
+(define_insn "*bswapsi2_internal"
   [(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")))]
+       (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")])
+  [(set_attr "length" "4,4,12")
+   (set_attr "type" "load,store,*")])
 
 (define_split
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
                   (const_int 16)))]
   "")
 
+(define_expand "bswapdi2"
+  [(parallel [(set (match_operand:DI 0 "reg_or_mem_operand" "")
+                  (bswap:DI
+                   (match_operand:DI 1 "reg_or_mem_operand" "")))
+             (clobber (match_scratch:DI 2 ""))
+             (clobber (match_scratch:DI 3 ""))
+             (clobber (match_scratch:DI 4 ""))])]
+  ""
+{
+  if (!REG_P (operands[0]) && !REG_P (operands[1]))
+    operands[1] = force_reg (DImode, operands[1]);
+
+  if (!TARGET_POWERPC64)
+    {
+      /* 32-bit mode needs fewer scratch registers, but 32-bit addressing mode
+        that uses 64-bit registers needs the same scratch registers as 64-bit
+        mode.  */
+      emit_insn (gen_bswapdi2_32bit (operands[0], operands[1]));
+      DONE;
+    }
+})
+
+;; Power7/cell has ldbrx/stdbrx, so use it directly
+(define_insn "*bswapdi2_ldbrx"
+  [(set (match_operand:DI 0 "reg_or_mem_operand" "=&r,Z,??&r")
+       (bswap:DI (match_operand:DI 1 "reg_or_mem_operand" "Z,r,r")))
+   (clobber (match_scratch:DI 2 "=X,X,&r"))
+   (clobber (match_scratch:DI 3 "=X,X,&r"))
+   (clobber (match_scratch:DI 4 "=X,X,&r"))]
+  "TARGET_POWERPC64 && TARGET_LDBRX
+   && (REG_P (operands[0]) || REG_P (operands[1]))"
+  "@
+   ldbrx %0,%y1
+   stdbrx %1,%y0
+   #"
+  [(set_attr "length" "4,4,36")
+   (set_attr "type" "load,store,*")])
+
+;; Non-power7/cell, fall back to use lwbrx/stwbrx
+(define_insn "*bswapdi2_64bit"
+  [(set (match_operand:DI 0 "reg_or_mem_operand" "=&r,Z,??&r")
+       (bswap:DI (match_operand:DI 1 "reg_or_mem_operand" "Z,r,r")))
+   (clobber (match_scratch:DI 2 "=&b,&b,&r"))
+   (clobber (match_scratch:DI 3 "=&r,&r,&r"))
+   (clobber (match_scratch:DI 4 "=&r,X,&r"))]
+  "TARGET_POWERPC64 && !TARGET_LDBRX
+   && (REG_P (operands[0]) || REG_P (operands[1]))"
+  "#"
+  [(set_attr "length" "16,12,36")])
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (bswap:DI (match_operand:DI 1 "indexed_or_indirect_operand" "")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+   (clobber (match_operand:DI 3 "gpc_reg_operand" ""))
+   (clobber (match_operand:DI 4 "gpc_reg_operand" ""))]
+  "TARGET_POWERPC64 && !TARGET_LDBRX && reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx dest   = operands[0];
+  rtx src    = operands[1];
+  rtx op2    = operands[2];
+  rtx op3    = operands[3];
+  rtx op4    = operands[4];
+  rtx op3_32 = simplify_gen_subreg (SImode, op3, DImode, 4);
+  rtx op4_32 = simplify_gen_subreg (SImode, op4, DImode, 4);
+  rtx addr1;
+  rtx addr2;
+  rtx word_high;
+  rtx word_low;
+
+  addr1 = XEXP (src, 0);
+  if (GET_CODE (addr1) == PLUS)
+    {
+      emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4)));
+      addr2 = gen_rtx_PLUS (Pmode, op2, XEXP (addr1, 1));
+    }
+  else
+    {
+      emit_move_insn (op2, GEN_INT (4));
+      addr2 = gen_rtx_PLUS (Pmode, op2, addr1);
+    }
+
+  if (BYTES_BIG_ENDIAN)
+    {
+      word_high = change_address (src, SImode, addr1);
+      word_low  = change_address (src, SImode, addr2);
+    }
+  else
+    {
+      word_high = change_address (src, SImode, addr2);
+      word_low  = change_address (src, SImode, addr1);
+    }
+
+  emit_insn (gen_bswapsi2 (op3_32, word_low));
+  emit_insn (gen_bswapsi2 (op4_32, word_high));
+  emit_insn (gen_ashldi3 (dest, op3, GEN_INT (32)));
+  emit_insn (gen_iordi3 (dest, dest, op4));
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "indexed_or_indirect_operand" "")
+       (bswap:DI (match_operand:DI 1 "gpc_reg_operand" "")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+   (clobber (match_operand:DI 3 "gpc_reg_operand" ""))
+   (clobber (match_operand:DI 4 "" ""))]
+  "TARGET_POWERPC64 && !TARGET_LDBRX && reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx dest   = operands[0];
+  rtx src    = operands[1];
+  rtx op2    = operands[2];
+  rtx op3    = operands[3];
+  rtx src_si = simplify_gen_subreg (SImode, src, DImode, 4);
+  rtx op3_si = simplify_gen_subreg (SImode, op3, DImode, 4);
+  rtx addr1;
+  rtx addr2;
+  rtx word_high;
+  rtx word_low;
+
+  addr1 = XEXP (dest, 0);
+  if (GET_CODE (addr1) == PLUS)
+    {
+      emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4)));
+      addr2 = gen_rtx_PLUS (Pmode, op2, XEXP (addr1, 1));
+    }
+  else
+    {
+      emit_move_insn (op2, GEN_INT (4));
+      addr2 = gen_rtx_PLUS (Pmode, op2, addr1);
+    }
+
+  emit_insn (gen_lshrdi3 (op3, src, GEN_INT (32)));
+  if (BYTES_BIG_ENDIAN)
+    {
+      word_high = change_address (dest, SImode, addr1);
+      word_low  = change_address (dest, SImode, addr2);
+      emit_insn (gen_bswapsi2 (word_high, src_si));
+      emit_insn (gen_bswapsi2 (word_low, op3_si));
+    }
+  else
+    {
+      word_high = change_address (dest, SImode, addr2);
+      word_low  = change_address (dest, SImode, addr1);
+      emit_insn (gen_bswapsi2 (word_low, src_si));
+      emit_insn (gen_bswapsi2 (word_high, op3_si));
+    }
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (bswap:DI (match_operand:DI 1 "gpc_reg_operand" "")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
+   (clobber (match_operand:DI 3 "gpc_reg_operand" ""))
+   (clobber (match_operand:DI 4 "" ""))]
+  "TARGET_POWERPC64 && reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx dest    = operands[0];
+  rtx src     = operands[1];
+  rtx op2     = operands[2];
+  rtx op3     = operands[3];
+  rtx dest_si = simplify_gen_subreg (SImode, dest, DImode, 4);
+  rtx src_si  = simplify_gen_subreg (SImode, src, DImode, 4);
+  rtx op2_si  = simplify_gen_subreg (SImode, op2, DImode, 4);
+  rtx op3_si  = simplify_gen_subreg (SImode, op3, DImode, 4);
+
+  emit_insn (gen_lshrdi3 (op2, src, GEN_INT (32)));
+  emit_insn (gen_bswapsi2 (dest_si, src_si));
+  emit_insn (gen_bswapsi2 (op3_si, op2_si));
+  emit_insn (gen_ashldi3 (dest, dest, GEN_INT (32)));
+  emit_insn (gen_iordi3 (dest, dest, op3));
+}")
+
+(define_insn "bswapdi2_32bit"
+  [(set (match_operand:DI 0 "reg_or_mem_operand" "=&r,Z,??&r")
+       (bswap:DI (match_operand:DI 1 "reg_or_mem_operand" "Z,r,r")))
+   (clobber (match_scratch:SI 2 "=&b,&b,X"))]
+  "!TARGET_POWERPC64 && (REG_P (operands[0]) || REG_P (operands[1]))"
+  "#"
+  [(set_attr "length" "16,12,36")])
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (bswap:DI (match_operand:DI 1 "indexed_or_indirect_operand" "")))
+   (clobber (match_operand:SI 2 "gpc_reg_operand" ""))]
+  "!TARGET_POWERPC64 && reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx dest   = operands[0];
+  rtx src    = operands[1];
+  rtx op2    = operands[2];
+  rtx dest_hi = simplify_gen_subreg (SImode, dest, DImode, 0);
+  rtx dest_lo = simplify_gen_subreg (SImode, dest, DImode, 4);
+  rtx addr1;
+  rtx addr2;
+  rtx word_high;
+  rtx word_low;
+
+  addr1 = XEXP (src, 0);
+  if (GET_CODE (addr1) == PLUS)
+    {
+      emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4)));
+      addr2 = gen_rtx_PLUS (SImode, op2, XEXP (addr1, 1));
+    }
+  else
+    {
+      emit_move_insn (op2, GEN_INT (4));
+      addr2 = gen_rtx_PLUS (SImode, op2, addr1);
+    }
+
+  if (BYTES_BIG_ENDIAN)
+    {
+      word_high = change_address (src, SImode, addr1);
+      word_low  = change_address (src, SImode, addr2);
+    }
+  else
+    {
+      word_high = change_address (src, SImode, addr2);
+      word_low  = change_address (src, SImode, addr1);
+    }
+
+  emit_insn (gen_bswapsi2 (dest_hi, word_low));
+  emit_insn (gen_bswapsi2 (dest_lo, word_high));
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "indexed_or_indirect_operand" "")
+       (bswap:DI (match_operand:DI 1 "gpc_reg_operand" "")))
+   (clobber (match_operand:SI 2 "gpc_reg_operand" ""))]
+  "!TARGET_POWERPC64 && reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx dest     = operands[0];
+  rtx src      = operands[1];
+  rtx op2      = operands[2];
+  rtx src_high = simplify_gen_subreg (SImode, src, DImode, 0);
+  rtx src_low  = simplify_gen_subreg (SImode, src, DImode, 4);
+  rtx addr1;
+  rtx addr2;
+  rtx word_high;
+  rtx word_low;
+
+  addr1 = XEXP (dest, 0);
+  if (GET_CODE (addr1) == PLUS)
+    {
+      emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4)));
+      addr2 = gen_rtx_PLUS (SImode, op2, XEXP (addr1, 1));
+    }
+  else
+    {
+      emit_move_insn (op2, GEN_INT (4));
+      addr2 = gen_rtx_PLUS (SImode, op2, addr1);
+    }
+
+  if (BYTES_BIG_ENDIAN)
+    {
+      word_high = change_address (dest, SImode, addr1);
+      word_low  = change_address (dest, SImode, addr2);
+    }
+  else
+    {
+      word_high = change_address (dest, SImode, addr2);
+      word_low  = change_address (dest, SImode, addr1);
+    }
+
+  emit_insn (gen_bswapsi2 (word_high, src_low));
+  emit_insn (gen_bswapsi2 (word_low, src_high));
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (bswap:DI (match_operand:DI 1 "gpc_reg_operand" "")))
+   (clobber (match_operand:SI 2 "" ""))]
+  "!TARGET_POWERPC64 && reload_completed"
+  [(const_int 0)]
+  "
+{
+  rtx dest      = operands[0];
+  rtx src       = operands[1];
+  rtx src_high  = simplify_gen_subreg (SImode, src, DImode, 0);
+  rtx src_low   = simplify_gen_subreg (SImode, src, DImode, 4);
+  rtx dest_high = simplify_gen_subreg (SImode, dest, DImode, 0);
+  rtx dest_low  = simplify_gen_subreg (SImode, dest, DImode, 4);
+
+  emit_insn (gen_bswapsi2 (dest_high, src_low));
+  emit_insn (gen_bswapsi2 (dest_low, src_high));
+}")
+
 (define_expand "mulsi3"
   [(use (match_operand:SI 0 "gpc_reg_operand" ""))
    (use (match_operand:SI 1 "gpc_reg_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "")
                             (match_operand:SI 2 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "")
                             (match_operand:SI 2 "gpc_reg_operand" ""))
                    (const_int 0)))
    {srai|sra<wd>i} %3,%1,%p2\;{aze.|addze.} %3,%3
    #"
   [(set_attr "type" "compare")
-   (set_attr "length" "8,12")])
+   (set_attr "length" "8,12")
+   (set_attr "cell_micro" "not")])
 
 (define_split
   [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
    {srai|sra<wd>i} %0,%1,%p2\;{aze.|addze.} %0,%0
    #"
   [(set_attr "type" "compare")
-   (set_attr "length" "8,12")])
+   (set_attr "length" "8,12")
+   (set_attr "cell_micro" "not")])
 
 (define_split
   [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
 ;; plain 'andi' (only 'andi.'), no plain 'andis', and there are all
 ;; those rotate-and-mask operations.  Thus, the AND insns come first.
 
-(define_insn "andsi3"
+(define_expand "andsi3"
+  [(parallel
+    [(set (match_operand:SI 0 "gpc_reg_operand" "")
+         (and:SI (match_operand:SI 1 "gpc_reg_operand" "")
+                 (match_operand:SI 2 "and_operand" "")))
+     (clobber (match_scratch:CC 3 ""))])]
+  ""
+  "")
+
+(define_insn "andsi3_mc"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
        (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
                (match_operand:SI 2 "and_operand" "?r,T,K,L")))
    (clobber (match_scratch:CC 3 "=X,X,x,x"))]
-  ""
+  "rs6000_gen_cell_microcode"
   "@
    and %0,%1,%2
    {rlinm|rlwinm} %0,%1,0,%m2,%M2
    {andil.|andi.} %0,%1,%b2
    {andiu.|andis.} %0,%1,%u2"
-  [(set_attr "type" "*,*,compare,compare")])
+  [(set_attr "type" "*,*,fast_compare,fast_compare")])
+
+(define_insn "andsi3_nomc"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+       (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")
+               (match_operand:SI 2 "and_operand" "?r,T")))
+   (clobber (match_scratch:CC 3 "=X,X"))]
+  "!rs6000_gen_cell_microcode"
+  "@
+   and %0,%1,%2
+   {rlinm|rlwinm} %0,%1,0,%m2,%M2")
+
+(define_insn "andsi3_internal0_nomc"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
+        (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")
+                (match_operand:SI 2 "and_operand" "?r,T")))]
+  "!rs6000_gen_cell_microcode"
+  "@
+   and %0,%1,%2
+   {rlinm|rlwinm} %0,%1,0,%m2,%M2")
+
 
 ;; Note to set cr's other than cr0 we do the and immediate and then
 ;; the test again -- this avoids a mfcr which on the higher end
 ;; machines causes an execution serialization
 
-(define_insn "*andsi3_internal2"
+(define_insn "*andsi3_internal2_mc"
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y")
        (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r")
                            (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T"))
                    (const_int 0)))
    (clobber (match_scratch:SI 3 "=r,r,r,r,r,r,r,r"))
    (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))]
-  "TARGET_32BIT"
+  "TARGET_32BIT && rs6000_gen_cell_microcode"
   "@
    and. %3,%1,%2
    {andil.|andi.} %3,%1,%b2
    #
    #
    #"
-  [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare")
+  [(set_attr "type" "fast_compare,fast_compare,fast_compare,delayed_compare,\
+                    compare,compare,compare,compare")
    (set_attr "length" "4,4,4,4,8,8,8,8")])
 
-(define_insn "*andsi3_internal3"
+(define_insn "*andsi3_internal3_mc"
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y")
        (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r")
                            (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T"))
                    (const_int 0)))
    (clobber (match_scratch:SI 3 "=r,r,r,r,r,r,r,r"))
    (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_gen_cell_microcode"
   "@
    #
    {andil.|andi.} %3,%1,%b2
    #
    #
    #"
-  [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare")
+  [(set_attr "type" "compare,fast_compare,fast_compare,delayed_compare,compare,\
+                    compare,compare,compare")
    (set_attr "length" "8,4,4,4,8,8,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "")
                             (match_operand:GPR 2 "and_operand" ""))
                    (const_int 0)))
        (and:SI (match_dup 1)
                (match_dup 2)))
    (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))]
-  "TARGET_32BIT"
+  "TARGET_32BIT && rs6000_gen_cell_microcode"
   "@
    and. %0,%1,%2
    {andil.|andi.} %0,%1,%b2
    #
    #
    #"
-  [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare")
+  [(set_attr "type" "fast_compare,fast_compare,fast_compare,delayed_compare,\
+                    compare,compare,compare,compare")
    (set_attr "length" "4,4,4,4,8,8,8,8")])
 
-(define_insn "*andsi3_internal5"
+(define_insn "*andsi3_internal5_mc"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y")
        (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r")
                            (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T"))
        (and:SI (match_dup 1)
                (match_dup 2)))
    (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_gen_cell_microcode"
   "@
    #
    {andil.|andi.} %0,%1,%b2
    #
    #
    #"
-  [(set_attr "type" "compare,compare,compare,delayed_compare,compare,compare,compare,compare")
+  [(set_attr "type" "compare,fast_compare,fast_compare,delayed_compare,compare,\
+                    compare,compare,compare")
    (set_attr "length" "8,4,4,4,8,8,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "and_operand" ""))
                    (const_int 0)))
   "@
    %q4. %3,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:SI 4 "boolean_operator"
         [(match_operand:SI 1 "gpc_reg_operand" "")
          (match_operand:SI 2 "gpc_reg_operand" "")])
   "@
    %q4. %0,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:SI 4 "boolean_operator"
         [(match_operand:SI 1 "gpc_reg_operand" "")
          (match_operand:SI 2 "gpc_reg_operand" "")])
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:SI 4 "boolean_operator"
         [(not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
          (match_operand:SI 2 "gpc_reg_operand" "")])
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:SI 4 "boolean_operator"
         [(not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
          (match_operand:SI 2 "gpc_reg_operand" "")])
   "@
    %q4. %3,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:SI 4 "boolean_operator"
         [(not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
          (not:SI (match_operand:SI 2 "gpc_reg_operand" ""))])
   "@
    %q4. %0,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:SI 4 "boolean_operator"
         [(not:SI (match_operand:SI 1 "gpc_reg_operand" ""))
          (not:SI (match_operand:SI 2 "gpc_reg_operand" ""))])
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "")
                         (match_operand:SI 2 "const_int_operand" "")
                         (match_operand:SI 3 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "")
                         (match_operand:SI 2 "const_int_operand" "")
                         (match_operand:SI 3 "const_int_operand" ""))
                         (match_operand:SI 3 "const_int_operand" "i"))
                    (const_int 0)))
    (clobber (match_scratch:DI 4 "=r"))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_gen_cell_microcode"
   "*
 {
   int start = INTVAL (operands[3]) & 63;
                    (const_int 0)))
    (set (match_operand:DI 0 "gpc_reg_operand" "=r")
        (zero_extract:DI (match_dup 1) (match_dup 2) (match_dup 3)))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_gen_cell_microcode"
   "*
 {
   int start = INTVAL (operands[3]) & 63;
    {rlinm|rlwinm} %0,%1,%h2,0xffffffff"
   [(set_attr "type" "var_shift_rotate,integer")])
 
+(define_insn "*rotlsi3_64"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+       (zero_extend:DI
+           (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+                      (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))]
+  "TARGET_64BIT"
+  "@
+   {rlnm|rlwnm} %0,%1,%2,0xffffffff
+   {rlinm|rlwinm} %0,%1,%h2,0xffffffff"
+  [(set_attr "type" "var_shift_rotate,integer")])
+
 (define_insn "*rotlsi3_internal2"
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
        (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
                               (match_operand:SI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
                               (match_operand:SI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:SI
                     (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
                                (match_operand:SI 2 "reg_or_cint_operand" ""))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:SI
                     (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
                                (match_operand:SI 2 "reg_or_cint_operand" ""))
          (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r")
                     (match_operand:SI 2 "reg_or_cint_operand" "ri")) 0)))]
   ""
-  "{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xff")
+  "{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xff"
+  [(set (attr "cell_micro")
+     (if_then_else (match_operand:SI 2 "const_int_operand" "")
+       (const_string "not")
+       (const_string "always")))])
 
 (define_insn "*rotlsi3_internal8"
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI
                     (subreg:QI
                      (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI
                     (subreg:QI
                      (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI
                     (subreg:HI
                      (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:SI
                     (subreg:HI
                      (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "")
    {sli|slwi} %0,%1,%h2"
   [(set_attr "type" "var_shift_rotate,shift")])
 
+(define_insn "*ashlsi3_64"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+       (zero_extend:DI
+           (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+                      (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))]
+  "TARGET_POWERPC64"
+  "@
+   {sl|slw} %0,%1,%2
+   {sli|slwi} %0,%1,%h2"
+  [(set_attr "type" "var_shift_rotate,shift")])
+
 (define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
        (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "const_int_operand" ""))
   {sri|srwi} %0,%1,%h2"
   [(set_attr "type" "integer,var_shift_rotate,shift")])
 
+(define_insn "*lshrsi3_64"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+       (zero_extend:DI
+           (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+                        (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))]
+  "TARGET_POWERPC64"
+  "@
+  {sr|srw} %0,%1,%2
+  {sri|srwi} %0,%1,%h2"
+  [(set_attr "type" "var_shift_rotate,shift")])
+
 (define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,?y,?y,?y")
        (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r,r,r")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
                              (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
                              (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (zero_extend:SI
          (subreg:QI
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (zero_extend:SI
          (subreg:QI
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (zero_extend:SI
          (subreg:HI
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (zero_extend:SI
          (subreg:HI
    {srai|srawi} %0,%1,%h2"
   [(set_attr "type" "var_shift_rotate,shift")])
 
+(define_insn "*ashrsi3_64"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r")
+       (sign_extend:DI
+           (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
+                        (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))]
+  "TARGET_POWERPC64"
+  "@
+   {sra|sraw} %0,%1,%2
+   {srai|srawi} %0,%1,%h2"
+  [(set_attr "type" "var_shift_rotate,shift")])
+
 (define_insn ""
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y")
        (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
                                 (match_operand:SI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
   [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare")
    (set_attr "length" "4,4,8,8")])
 \f
+;; Builtins to replace a division to generate FRE reciprocal estimate
+;; instructions and the necessary fixup instructions
+(define_expand "recip<mode>3"
+  [(match_operand:RECIPF 0 "gpc_reg_operand" "")
+   (match_operand:RECIPF 1 "gpc_reg_operand" "")
+   (match_operand:RECIPF 2 "gpc_reg_operand" "")]
+  "RS6000_RECIP_HAVE_RE_P (<MODE>mode)"
+{
+   rs6000_emit_swdiv (operands[0], operands[1], operands[2], false);
+   DONE;
+})
+
+;; Split to create division from FRE/FRES/etc. and fixup instead of the normal
+;; hardware division.  This is only done before register allocation and with
+;; -ffast-math.  This must appear before the divsf3/divdf3 insns.
+(define_split
+  [(set (match_operand:RECIPF 0 "gpc_reg_operand" "")
+       (div:RECIPF (match_operand 1 "gpc_reg_operand" "")
+                   (match_operand 2 "gpc_reg_operand" "")))]
+  "RS6000_RECIP_AUTO_RE_P (<MODE>mode)
+   && can_create_pseudo_p () && optimize_insn_for_speed_p ()
+   && flag_finite_math_only && !flag_trapping_math && flag_reciprocal_math"
+  [(const_int 0)]
+{
+  rs6000_emit_swdiv (operands[0], operands[1], operands[2], true);
+  DONE;
+})
+
+;; Builtins to replace 1/sqrt(x) with instructions using RSQRTE and the
+;; appropriate fixup.
+(define_expand "rsqrt<mode>2"
+  [(match_operand:RECIPF 0 "gpc_reg_operand" "")
+   (match_operand:RECIPF 1 "gpc_reg_operand" "")]
+  "RS6000_RECIP_HAVE_RSQRTE_P (<MODE>mode)"
+{
+  rs6000_emit_swrsqrt (operands[0], operands[1]);
+  DONE;
+})
+\f
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "")
                                 (match_operand:SI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
 (define_expand "extendsfdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (float_extend:DF (match_operand:SF 1 "reg_or_none500mem_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn_and_split "*extendsfdf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f,?f,f")
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d,d")
        (float_extend:DF (match_operand:SF 1 "reg_or_mem_operand" "0,f,m")))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "@
    #
    fmr %0,%1
 (define_expand "truncdfsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn "*truncdfsf2_fpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+       (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "frsp %0,%1"
   [(set_attr "type" "fp")])
 
 (define_expand "negsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (neg:SF (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT"
   "")
 
 (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 && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "fneg %0,%1"
   [(set_attr "type" "fp")])
 
 (define_expand "abssf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
        (abs:SF (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT"
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT"
   "")
 
 (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 && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_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 && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_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"
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_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_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "fadds %0,%1,%2"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_addsub_s")])
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
   [(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"
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_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_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "fsubs %0,%1,%2"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_addsub_s")])
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
   [(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"
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_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_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "fmuls %0,%1,%2"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_mul_s")])
 
 (define_insn ""
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
   [(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"
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU"
   "")
 
 (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_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU"
   "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_HARD_FLOAT && TARGET_FPRS"
+  "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU"
   "{fd|fdiv} %0,%1,%2"
   [(set_attr "type" "ddiv")])
 
-(define_expand "recipsf3"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")
-                   (match_operand:SF 2 "gpc_reg_operand" "f")]
-                  UNSPEC_FRES))]
-  "TARGET_RECIP && TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT && !optimize_size
-   && flag_finite_math_only && !flag_trapping_math"
-{
-   rs6000_emit_swdivsf (operands[0], operands[1], operands[2]);
-   DONE;
-})
-
 (define_insn "fres"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRES))]
-  "TARGET_PPC_GFXOPT && flag_finite_math_only"
+  "TARGET_FRES"
   "fres %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD"
-  "fmadds %0,%1,%2,%3"
-  [(set_attr "type" "fp")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD"
-  "{fma|fmadd} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD"
-  "fmsubs %0,%1,%2,%3"
-  [(set_attr "type" "fp")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD"
-  "{fms|fmsub} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (SFmode)"
-  "fnmadds %0,%1,%2,%3"
-  [(set_attr "type" "fp")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (minus:SF (mult:SF (neg: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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
-   && ! HONOR_SIGNED_ZEROS (SFmode)"
-  "fnmadds %0,%1,%2,%3"
-  [(set_attr "type" "fp")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD"
-  "{fnma|fnmadd} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
-
-(define_insn ""
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (minus:SF (mult:SF (neg: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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
-   && ! HONOR_SIGNED_ZEROS (SFmode)"
-  "{fnma|fnmadd} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
-
-(define_insn ""
+; builtin fmaf support
+(define_insn "*fmasf4_fpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (SFmode)"
-  "fnmsubs %0,%1,%2,%3"
-  [(set_attr "type" "fp")])
+       (fma: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_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
+{
+  return (TARGET_POWERPC
+         ? "fmadds %0,%1,%2,%3"
+         : "{fma|fmadd} %0,%1,%2,%3");
+}
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
+(define_insn "*fmssf4_fpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (minus:SF (match_operand:SF 3 "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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
-   && ! HONOR_SIGNED_ZEROS (SFmode)"
-  "fnmsubs %0,%1,%2,%3"
-  [(set_attr "type" "fp")])
+       (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f")
+               (match_operand:SF 2 "gpc_reg_operand" "f")
+               (neg:SF (match_operand:SF 3 "gpc_reg_operand" "f"))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
+{
+  return (TARGET_POWERPC
+         ? "fmsubs %0,%1,%2,%3"
+         : "{fms|fmsub} %0,%1,%2,%3");
+}
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
+(define_insn "*nfmasf4_fpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD"
-  "{fnms|fnmsub} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+       (neg:SF (fma: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_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
+{
+  return (TARGET_POWERPC
+         ? "fnmadds %0,%1,%2,%3"
+         : "{fnma|fnmadd} %0,%1,%2,%3");
+}
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
+(define_insn "*nfmssf4_fpr"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (minus:SF (match_operand:SF 3 "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_HARD_FLOAT && TARGET_FPRS && TARGET_FUSED_MADD
-   && ! HONOR_SIGNED_ZEROS (SFmode)"
-  "{fnms|fnmsub} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+       (neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f")
+                       (match_operand:SF 2 "gpc_reg_operand" "f")
+                       (neg:SF (match_operand:SF 3 "gpc_reg_operand" "f")))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
+{
+  return (TARGET_POWERPC
+         ? "fnmsubs %0,%1,%2,%3"
+         : "{fnms|fnmsub} %0,%1,%2,%3");
+}
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
 (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_HARD_FLOAT && TARGET_FPRS"
+  "(TARGET_PPC_GPOPT || TARGET_POWER2 || TARGET_XILINX_FPU)
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && !TARGET_SIMPLE_FPU"
   "")
 
 (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_HARD_FLOAT && TARGET_FPRS"
+  "(TARGET_PPC_GPOPT || TARGET_XILINX_FPU) && TARGET_HARD_FLOAT
+   && TARGET_FPRS && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU"
   "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_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_POWER2 && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU"
   "fsqrt %0,%1"
   [(set_attr "type" "dsqrt")])
 
-(define_expand "rsqrtsf2"
+(define_insn "*rsqrtsf_internal1"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")]
                   UNSPEC_RSQRT))]
-  "TARGET_RECIP && TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT && !optimize_size
-   && flag_finite_math_only && !flag_trapping_math"
-{
-  rs6000_emit_swrsqrtsf (operands[0], operands[1]);
-  DONE;
-})
-
-(define_insn "*rsqrt_internal1"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")]
-                  UNSPEC_RSQRT))]
-  "TARGET_HARD_FLOAT && TARGET_PPC_GFXOPT"
-  "frsqrte %0,%1"
+  "TARGET_FRSQRTES"
+  "frsqrtes %0,%1"
   [(set_attr "type" "fp")])
 
-(define_expand "copysignsf3"
+(define_expand "copysign<mode>3"
   [(set (match_dup 3)
-        (abs:SF (match_operand:SF 1 "gpc_reg_operand" "")))
+        (abs:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "")))
    (set (match_dup 4)
-       (neg:SF (abs:SF (match_dup 1))))
-   (set (match_operand:SF 0 "gpc_reg_operand" "")
-        (if_then_else:SF (ge (match_operand:SF 2 "gpc_reg_operand" "")
-                            (match_dup 5))
+       (neg:SFDF (abs:SFDF (match_dup 1))))
+   (set (match_operand:SFDF 0 "gpc_reg_operand" "")
+        (if_then_else:SFDF (ge (match_operand:SFDF 2 "gpc_reg_operand" "")
+                              (match_dup 5))
                         (match_dup 3)
                         (match_dup 4)))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS
-   && !HONOR_NANS (SFmode) && !HONOR_SIGNED_ZEROS (SFmode)"
-  {
-     operands[3] = gen_reg_rtx (SFmode);
-     operands[4] = gen_reg_rtx (SFmode);
-     operands[5] = CONST0_RTX (SFmode);
-  })
+  "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && ((TARGET_PPC_GFXOPT
+        && !HONOR_NANS (<MODE>mode)
+        && !HONOR_SIGNED_ZEROS (<MODE>mode))
+       || TARGET_CMPB
+       || VECTOR_UNIT_VSX_P (<MODE>mode))"
+{
+  if (TARGET_CMPB || VECTOR_UNIT_VSX_P (<MODE>mode))
+    {
+      emit_insn (gen_copysign<mode>3_fcpsgn (operands[0], operands[1],
+                                            operands[2]));
+      DONE;
+    }
 
-(define_expand "copysigndf3"
-  [(set (match_dup 3)
-        (abs:DF (match_operand:DF 1 "gpc_reg_operand" "")))
-   (set (match_dup 4)
-       (neg:DF (abs:DF (match_dup 1))))
-   (set (match_operand:DF 0 "gpc_reg_operand" "")
-        (if_then_else:DF (ge (match_operand:DF 2 "gpc_reg_operand" "")
-                            (match_dup 5))
-                        (match_dup 3)
-                        (match_dup 4)))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS
-   && !HONOR_NANS (DFmode) && !HONOR_SIGNED_ZEROS (DFmode)"
-  {
-     operands[3] = gen_reg_rtx (DFmode);
-     operands[4] = gen_reg_rtx (DFmode);
-     operands[5] = CONST0_RTX (DFmode);
+   operands[3] = gen_reg_rtx (<MODE>mode);
+   operands[4] = gen_reg_rtx (<MODE>mode);
+   operands[5] = CONST0_RTX (<MODE>mode);
   })
 
+;; Use an unspec rather providing an if-then-else in RTL, to prevent the
+;; compiler from optimizing -0.0
+(define_insn "copysign<mode>3_fcpsgn"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")
+                     (match_operand:SFDF 2 "gpc_reg_operand" "<rreg2>")]
+                    UNSPEC_COPYSIGN))]
+  "TARGET_CMPB && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "fcpsgn %0,%2,%1"
+  [(set_attr "type" "fp")])
+
 ;; 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
                             (match_operand:SF 2 "gpc_reg_operand" ""))
                         (match_dup 1)
                         (match_dup 2)))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && !flag_trapping_math"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_SINGLE_FLOAT && !flag_trapping_math"
   "{ rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); DONE;}")
 
 (define_expand "sminsf3"
                             (match_operand:SF 2 "gpc_reg_operand" ""))
                         (match_dup 2)
                         (match_dup 1)))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && !flag_trapping_math"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_SINGLE_FLOAT && !flag_trapping_math"
   "{ rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); DONE;}")
 
 (define_split
        (match_operator:SF 3 "min_max_operator"
         [(match_operand:SF 1 "gpc_reg_operand" "")
          (match_operand:SF 2 "gpc_reg_operand" "")]))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && !flag_trapping_math"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_SINGLE_FLOAT && !flag_trapping_math"
   [(const_int 0)]
   "
 { rs6000_emit_minmax (operands[0], GET_CODE (operands[3]),
   DONE;
 }")
 
-(define_expand "movsicc"
-   [(set (match_operand:SI 0 "gpc_reg_operand" "")
-        (if_then_else:SI (match_operand 1 "comparison_operator" "")
-                         (match_operand:SI 2 "gpc_reg_operand" "")
-                         (match_operand:SI 3 "gpc_reg_operand" "")))]
-  "TARGET_ISEL"
+(define_expand "mov<mode>cc"
+   [(set (match_operand:GPR 0 "gpc_reg_operand" "")
+        (if_then_else:GPR (match_operand 1 "comparison_operator" "")
+                          (match_operand:GPR 2 "gpc_reg_operand" "")
+                          (match_operand:GPR 3 "gpc_reg_operand" "")))]
+  "TARGET_ISEL<sel>"
   "
 {
   if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3]))
 ;; leave out the mode in operand 4 and use one pattern, but reload can
 ;; change the mode underneath our feet and then gets confused trying
 ;; to reload the value.
-(define_insn "isel_signed"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-       (if_then_else:SI
-        (match_operator 1 "comparison_operator"
+(define_insn "isel_signed_<mode>"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
+       (if_then_else:GPR
+        (match_operator 1 "scc_comparison_operator"
+                        [(match_operand:CC 4 "cc_reg_operand" "y,y")
+                         (const_int 0)])
+        (match_operand:GPR 2 "reg_or_cint_operand" "O,b")
+        (match_operand:GPR 3 "gpc_reg_operand" "r,r")))]
+  "TARGET_ISEL<sel>"
+  "*
+{ return output_isel (operands); }"
+  [(set_attr "type" "isel")
+   (set_attr "length" "4")])
+
+(define_insn "isel_unsigned_<mode>"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
+       (if_then_else:GPR
+        (match_operator 1 "scc_comparison_operator"
+                        [(match_operand:CCUNS 4 "cc_reg_operand" "y,y")
+                         (const_int 0)])
+        (match_operand:GPR 2 "reg_or_cint_operand" "O,b")
+        (match_operand:GPR 3 "gpc_reg_operand" "r,r")))]
+  "TARGET_ISEL<sel>"
+  "*
+{ return output_isel (operands); }"
+  [(set_attr "type" "isel")
+   (set_attr "length" "4")])
+
+;; These patterns can be useful for combine; they let combine know that
+;; isel can handle reversed comparisons so long as the operands are
+;; registers.
+
+(define_insn "*isel_reversed_signed_<mode>"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+       (if_then_else:GPR
+        (match_operator 1 "scc_rev_comparison_operator"
                         [(match_operand:CC 4 "cc_reg_operand" "y")
                          (const_int 0)])
-        (match_operand:SI 2 "gpc_reg_operand" "b")
-        (match_operand:SI 3 "gpc_reg_operand" "b")))]
-  "TARGET_ISEL"
+        (match_operand:GPR 2 "gpc_reg_operand" "b")
+        (match_operand:GPR 3 "gpc_reg_operand" "b")))]
+  "TARGET_ISEL<sel>"
   "*
 { return output_isel (operands); }"
-  [(set_attr "length" "4")])
+  [(set_attr "type" "isel")
+   (set_attr "length" "4")])
 
-(define_insn "isel_unsigned"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-       (if_then_else:SI
-        (match_operator 1 "comparison_operator"
+(define_insn "*isel_reversed_unsigned_<mode>"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+       (if_then_else:GPR
+        (match_operator 1 "scc_rev_comparison_operator"
                         [(match_operand:CCUNS 4 "cc_reg_operand" "y")
                          (const_int 0)])
-        (match_operand:SI 2 "gpc_reg_operand" "b")
-        (match_operand:SI 3 "gpc_reg_operand" "b")))]
-  "TARGET_ISEL"
+        (match_operand:GPR 2 "gpc_reg_operand" "b")
+        (match_operand:GPR 3 "gpc_reg_operand" "b")))]
+  "TARGET_ISEL<sel>"
   "*
 { return output_isel (operands); }"
-  [(set_attr "length" "4")])
+  [(set_attr "type" "isel")
+   (set_attr "length" "4")])
 
 (define_expand "movsfcc"
    [(set (match_operand:SF 0 "gpc_reg_operand" "")
         (if_then_else:SF (match_operand 1 "comparison_operator" "")
                          (match_operand:SF 2 "gpc_reg_operand" "")
                          (match_operand:SF 3 "gpc_reg_operand" "")))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "
 {
   if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3]))
                             (match_operand:SF 4 "zero_fp_constant" "F"))
                         (match_operand:SF 2 "gpc_reg_operand" "f")
                         (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_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")
+       (if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "d")
                             (match_operand:DF 4 "zero_fp_constant" "F"))
                         (match_operand:SF 2 "gpc_reg_operand" "f")
                         (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_SINGLE_FLOAT"
   "fsel %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
 (define_expand "negdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (neg:DF (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn "*negdf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (neg:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (neg:DF (match_operand:DF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "fneg %0,%1"
   [(set_attr "type" "fp")])
 
 (define_expand "absdf2"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (abs:DF (match_operand:DF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn "*absdf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (abs:DF (match_operand:DF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "fabs %0,%1"
   [(set_attr "type" "fp")])
 
 (define_insn "*nabsdf2_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (neg:DF (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f"))))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (neg:DF (abs:DF (match_operand:DF 1 "gpc_reg_operand" "d"))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "fnabs %0,%1"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (plus:DF (match_operand:DF 1 "gpc_reg_operand" "")
                 (match_operand:DF 2 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn "*adddf3_fpr"
-  [(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 && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (plus:DF (match_operand:DF 1 "gpc_reg_operand" "%d")
+                (match_operand:DF 2 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "{fa|fadd} %0,%1,%2"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_addsub_d")])
 
 (define_expand "subdf3"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (minus:DF (match_operand:DF 1 "gpc_reg_operand" "")
                  (match_operand:DF 2 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn "*subdf3_fpr"
-  [(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 && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (minus:DF (match_operand:DF 1 "gpc_reg_operand" "d")
+                 (match_operand:DF 2 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "{fs|fsub} %0,%1,%2"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_addsub_d")])
 
 (define_expand "muldf3"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (mult:DF (match_operand:DF 1 "gpc_reg_operand" "")
                 (match_operand:DF 2 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "")
 
 (define_insn "*muldf3_fpr"
-  [(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 && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d")
+                (match_operand:DF 2 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "{fm|fmul} %0,%1,%2"
-  [(set_attr "type" "dmul")])
+  [(set_attr "type" "dmul")
+   (set_attr "fp_type" "fp_mul_d")])
 
 (define_expand "divdf3"
   [(set (match_operand:DF 0 "gpc_reg_operand" "")
        (div:DF (match_operand:DF 1 "gpc_reg_operand" "")
                (match_operand:DF 2 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)
+   && !TARGET_SIMPLE_FPU"
   "")
 
 (define_insn "*divdf3_fpr"
-  [(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 && TARGET_FPRS"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (div:DF (match_operand:DF 1 "gpc_reg_operand" "d")
+               (match_operand:DF 2 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && !TARGET_SIMPLE_FPU
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "{fd|fdiv} %0,%1,%2"
   [(set_attr "type" "ddiv")])
 
-(define_expand "recipdf3"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")
-                   (match_operand:DF 2 "gpc_reg_operand" "f")]
-                  UNSPEC_FRES))]
-  "TARGET_RECIP && TARGET_HARD_FLOAT && TARGET_POPCNTB && !optimize_size
-   && flag_finite_math_only && !flag_trapping_math"
-{
-   rs6000_emit_swdivdf (operands[0], operands[1], operands[2]);
-   DONE;
-})
-
-(define_insn "fred"
+(define_insn "*fred_fpr"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
        (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRES))]
-  "TARGET_POPCNTB && flag_finite_math_only"
+  "TARGET_FRE && !VECTOR_UNIT_VSX_P (DFmode)"
   "fre %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn ""
+(define_insn "*rsqrtdf_internal1"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")]
+                  UNSPEC_RSQRT))]
+  "TARGET_FRSQRTE && !VECTOR_UNIT_VSX_P (DFmode)"
+  "frsqrte %0,%1"
+  [(set_attr "type" "fp")])
+
+; builtin fma support
+(define_insn "*fmadf4_fpr"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (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 && TARGET_FPRS && TARGET_FUSED_MADD"
+       (fma: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 && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && VECTOR_UNIT_NONE_P (DFmode)"
   "{fma|fmadd} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
+(define_insn "*fmsdf4_fpr"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (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 && TARGET_FPRS && TARGET_FUSED_MADD"
+       (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f")
+               (match_operand:DF 2 "gpc_reg_operand" "f")
+               (neg:DF (match_operand:DF 3 "gpc_reg_operand" "f"))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && VECTOR_UNIT_NONE_P (DFmode)"
   "{fms|fmsub} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
-
-(define_insn ""
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (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 && TARGET_FPRS && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (DFmode)"
-  "{fnma|fnmadd} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
+(define_insn "*nfmadf4_fpr"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (minus:DF (mult:DF (neg: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 && TARGET_FPRS && TARGET_FUSED_MADD
-   && ! HONOR_SIGNED_ZEROS (DFmode)"
+       (neg:DF (fma: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 && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && VECTOR_UNIT_NONE_P (DFmode)"
   "{fnma|fnmadd} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
+(define_insn "*nfmsdf4_fpr"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (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 && TARGET_FPRS && TARGET_FUSED_MADD
-   && HONOR_SIGNED_ZEROS (DFmode)"
+       (neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f")
+                       (match_operand:DF 2 "gpc_reg_operand" "f")
+                       (neg:DF (match_operand:DF 3 "gpc_reg_operand" "f")))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && VECTOR_UNIT_NONE_P (DFmode)"
   "{fnms|fnmsub} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn ""
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (minus:DF (match_operand:DF 3 "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 && TARGET_FPRS && TARGET_FUSED_MADD
-   && ! HONOR_SIGNED_ZEROS (DFmode)"
-  "{fnms|fnmsub} %0,%1,%2,%3"
-  [(set_attr "type" "dmul")])
+(define_expand "sqrtdf2"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "")
+       (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "")))]
+  "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_DOUBLE_FLOAT"
+  "")
 
-(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_HARD_FLOAT && TARGET_FPRS"
+(define_insn "*sqrtdf2_fpr"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "d")))]
+  "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "fsqrt %0,%1"
   [(set_attr "type" "dsqrt")])
 
                             (match_operand:DF 2 "gpc_reg_operand" ""))
                         (match_dup 1)
                         (match_dup 2)))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && !flag_trapping_math"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && !flag_trapping_math"
   "{ rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); DONE;}")
 
 (define_expand "smindf3"
                             (match_operand:DF 2 "gpc_reg_operand" ""))
                         (match_dup 2)
                         (match_dup 1)))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && !flag_trapping_math"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && !flag_trapping_math"
   "{ rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); DONE;}")
 
 (define_split
        (match_operator:DF 3 "min_max_operator"
         [(match_operand:DF 1 "gpc_reg_operand" "")
          (match_operand:DF 2 "gpc_reg_operand" "")]))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && !flag_trapping_math"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && !flag_trapping_math"
   [(const_int 0)]
   "
 { rs6000_emit_minmax (operands[0], GET_CODE (operands[3]),
         (if_then_else:DF (match_operand 1 "comparison_operator" "")
                          (match_operand:DF 2 "gpc_reg_operand" "")
                          (match_operand:DF 3 "gpc_reg_operand" "")))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "
 {
   if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3]))
 }")
 
 (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")
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "d")
                             (match_operand:DF 4 "zero_fp_constant" "F"))
-                        (match_operand:DF 2 "gpc_reg_operand" "f")
-                        (match_operand:DF 3 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS"
+                        (match_operand:DF 2 "gpc_reg_operand" "d")
+                        (match_operand:DF 3 "gpc_reg_operand" "d")))]
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "fsel %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
 (define_insn "*fselsfdf4"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
        (if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
                             (match_operand:SF 4 "zero_fp_constant" "F"))
-                        (match_operand:DF 2 "gpc_reg_operand" "f")
-                        (match_operand:DF 3 "gpc_reg_operand" "f")))]
-  "TARGET_PPC_GFXOPT"
+                        (match_operand:DF 2 "gpc_reg_operand" "d")
+                        (match_operand:DF 3 "gpc_reg_operand" "d")))]
+  "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_SINGLE_FLOAT"
   "fsel %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 \f
 ;; Conversions to and from floating-point.
 
-(define_expand "fixuns_truncsfsi2"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-       (unsigned_fix:SI (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS"
-  "")
-
-(define_expand "fix_truncsfsi2"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-       (fix:SI (match_operand:SF 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS"
-  "")
-
-; For each of these conversions, there is a define_expand, a define_insn
-; with a '#' template, and a define_split (with C code).  The idea is
-; to allow constant folding with the template of the define_insn,
-; then to have the insns split later (between sched1 and final).
-
-(define_expand "floatsidf2"
-  [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
-                  (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
-             (use (match_dup 2))
-             (use (match_dup 3))
-             (clobber (match_dup 4))
-             (clobber (match_dup 5))
-             (clobber (match_dup 6))])]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+; We don't define lfiwax/lfiwzx with the normal definition, because we
+; don't want to support putting SImode in FPR registers.
+(define_insn "lfiwax"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")]
+                  UNSPEC_LFIWAX))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX"
+  "lfiwax %0,%y1"
+  [(set_attr "type" "fpload")])
+
+; This split must be run before register allocation because it allocates the
+; memory slot that is needed to move values to/from the FPR.  We don't allocate
+; it earlier to allow for the combiner to merge insns together where it might
+; not be needed and also in case the insns are deleted as dead code.
+
+(define_insn_and_split "floatsi<mode>2_lfiwax"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d")
+       (float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+   && <SI_CONVERT_FP> && can_create_pseudo_p ()"
+  "#"
+  ""
+  [(pc)]
   "
 {
-  if (TARGET_E500_DOUBLE)
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx tmp;
+
+  if (!MEM_P (src) && TARGET_MFPGPR && TARGET_POWERPC64)
+    tmp = convert_to_mode (DImode, src, false);
+  else
     {
-      emit_insn (gen_spe_floatsidf2 (operands[0], operands[1]));
-      DONE;
+      tmp = operands[2];
+      if (GET_CODE (tmp) == SCRATCH)
+       tmp = gen_reg_rtx (DImode);
+      if (MEM_P (src))
+       {
+         src = rs6000_address_for_fpconvert (src);
+         emit_insn (gen_lfiwax (tmp, src));
+       }
+      else
+       {
+         rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+         emit_move_insn (stack, src);
+         emit_insn (gen_lfiwax (tmp, stack));
+       }
     }
-  if (TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS)
-    {
-      rtx t1 = gen_reg_rtx (DImode);
-      emit_insn (gen_floatsidf_ppc64_mfpgpr (operands[0], operands[1], t1));
-      DONE;
+  emit_insn (gen_floatdi<mode>2 (dest, tmp));
+  DONE;
+}"
+  [(set_attr "length" "12")
+   (set_attr "type" "fpload")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax_mem"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>")
+       (float:SFDF
+        (sign_extend:DI
+         (match_operand:SI 1 "memory_operand" "Z,Z"))))
+   (clobber (match_scratch:DI 2 "=0,d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+   && <SI_CONVERT_FP>"
+  "#"
+  ""
+  [(pc)]
+  "
+{
+  operands[1] = rs6000_address_for_fpconvert (operands[1]);
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (DImode);
+  emit_insn (gen_lfiwax (operands[2], operands[1]));
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")
+   (set_attr "type" "fpload")])
+
+(define_insn "lfiwzx"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")]
+                  UNSPEC_LFIWZX))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX"
+  "lfiwzx %0,%y1"
+  [(set_attr "type" "fpload")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d")
+       (unsigned_float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+   && <SI_CONVERT_FP>"
+  "#"
+  ""
+  [(pc)]
+  "
+{
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx tmp;
+
+  if (!MEM_P (src) && TARGET_MFPGPR && TARGET_POWERPC64)
+    tmp = convert_to_mode (DImode, src, true);
+  else
+    {
+      tmp = operands[2];
+      if (GET_CODE (tmp) == SCRATCH)
+       tmp = gen_reg_rtx (DImode);
+      if (MEM_P (src))
+       {
+         src = rs6000_address_for_fpconvert (src);
+         emit_insn (gen_lfiwzx (tmp, src));
+       }
+      else
+       {
+         rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+         emit_move_insn (stack, src);
+         emit_insn (gen_lfiwzx (tmp, stack));
+       }
     }
-  if (TARGET_POWERPC64)
+  emit_insn (gen_floatdi<mode>2 (dest, tmp));
+  DONE;
+}"
+  [(set_attr "length" "12")
+   (set_attr "type" "fpload")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>")
+       (unsigned_float:SFDF
+        (zero_extend:DI
+         (match_operand:SI 1 "memory_operand" "Z,Z"))))
+   (clobber (match_scratch:DI 2 "=0,d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+   && <SI_CONVERT_FP>"
+  "#"
+  ""
+  [(pc)]
+  "
+{
+  operands[1] = rs6000_address_for_fpconvert (operands[1]);
+  if (GET_CODE (operands[2]) == SCRATCH)
+    operands[2] = gen_reg_rtx (DImode);
+  emit_insn (gen_lfiwzx (operands[2], operands[1]));
+  emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")
+   (set_attr "type" "fpload")])
+
+; For each of these conversions, there is a define_expand, a define_insn
+; with a '#' template, and a define_split (with C code).  The idea is
+; to allow constant folding with the template of the define_insn,
+; then to have the insns split later (between sched1 and final).
+
+(define_expand "floatsidf2"
+  [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
+                  (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
+             (use (match_dup 2))
+             (use (match_dup 3))
+             (clobber (match_dup 4))
+             (clobber (match_dup 5))
+             (clobber (match_dup 6))])]
+  "TARGET_HARD_FLOAT 
+   && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
+  "
+{
+  if (TARGET_E500_DOUBLE)
     {
-      rtx mem = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
-      rtx t1 = gen_reg_rtx (DImode);
-      rtx t2 = gen_reg_rtx (DImode);
-      emit_insn (gen_floatsidf_ppc64 (operands[0], operands[1], mem, t1, t2));
+      if (!REG_P (operands[1]))
+       operands[1] = force_reg (SImode, operands[1]);
+      emit_insn (gen_spe_floatsidf2 (operands[0], operands[1]));
+      DONE;
+    }
+  else if (TARGET_LFIWAX && TARGET_FCFID)
+    {
+      emit_insn (gen_floatsidf2_lfiwax (operands[0], operands[1]));
+      DONE;
+    }
+  else if (TARGET_FCFID)
+    {
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+       dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, false);
+      emit_insn (gen_floatdidf2 (operands[0], dreg));
       DONE;
     }
 
+  if (!REG_P (operands[1]))
+    operands[1] = force_reg (SImode, operands[1]);
   operands[2] = force_reg (SImode, GEN_INT (0x43300000));
   operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503601774854144\", DFmode));
-  operands[4] = assign_stack_temp (DFmode, GET_MODE_SIZE (DFmode), 0);
+  operands[4] = rs6000_allocate_stack_temp (DFmode, true, false);
   operands[5] = gen_reg_rtx (DFmode);
   operands[6] = gen_reg_rtx (SImode);
 }")
 
 (define_insn_and_split "*floatsidf2_internal"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=&f")
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=&d")
        (float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
    (use (match_operand:SI 2 "gpc_reg_operand" "r"))
-   (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+   (use (match_operand:DF 3 "gpc_reg_operand" "d"))
    (clobber (match_operand:DF 4 "offsettable_mem_operand" "=o"))
-   (clobber (match_operand:DF 5 "gpc_reg_operand" "=&f"))
+   (clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))
    (clobber (match_operand:SI 6 "gpc_reg_operand" "=&r"))]
-  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "! TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "#"
-  "&& (can_create_pseudo_p () || offsettable_nonstrict_memref_p (operands[4]))"
+  ""
   [(pc)]
   "
 {
   emit_insn (gen_subdf3 (operands[0], operands[5], operands[3]));
   DONE;
 }"
-  [(set_attr "length" "24")])
+  [(set_attr "length" "24")
+   (set_attr "type" "fp")])
 
+;; If we don't have a direct conversion to single precision, don't enable this
+;; conversion for 32-bit without fast math, because we don't have the insn to
+;; generate the fixup swizzle to avoid double rounding problems.
 (define_expand "floatunssisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
-        (unsigned_float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS"
-  "")
+        (unsigned_float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT
+   && (!TARGET_FPRS
+       || (TARGET_FPRS
+          && ((TARGET_FCFIDUS && TARGET_LFIWZX)
+              || (TARGET_DOUBLE_FLOAT && TARGET_FCFID
+                  && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))"
+  "
+{
+  if (!TARGET_FPRS)
+    {
+      if (!REG_P (operands[1]))
+       operands[1] = force_reg (SImode, operands[1]);
+    }
+  else if (TARGET_LFIWZX && TARGET_FCFIDUS)
+    {
+      emit_insn (gen_floatunssisf2_lfiwzx (operands[0], operands[1]));
+      DONE;
+    }
+  else
+    {
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+       dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, true);
+      emit_insn (gen_floatdisf2 (operands[0], dreg));
+      DONE;
+    }
+}")
 
 (define_expand "floatunssidf2"
   [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
-                  (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+                  (unsigned_float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
              (use (match_dup 2))
              (use (match_dup 3))
              (clobber (match_dup 4))
              (clobber (match_dup 5))])]
-  "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+  "TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
   "
 {
   if (TARGET_E500_DOUBLE)
     {
+      if (!REG_P (operands[1]))
+       operands[1] = force_reg (SImode, operands[1]);
       emit_insn (gen_spe_floatunssidf2 (operands[0], operands[1]));
       DONE;
     }
-  if (TARGET_POWERPC64)
+  else if (TARGET_LFIWZX && TARGET_FCFID)
     {
-      rtx mem = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
-      rtx t1 = gen_reg_rtx (DImode);
-      rtx t2 = gen_reg_rtx (DImode);
-      emit_insn (gen_floatunssidf_ppc64 (operands[0], operands[1], mem,
-                                        t1, t2));
+      emit_insn (gen_floatunssidf2_lfiwzx (operands[0], operands[1]));
+      DONE;
+    }
+  else if (TARGET_FCFID)
+    {
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+       dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, true);
+      emit_insn (gen_floatdidf2 (operands[0], dreg));
       DONE;
     }
 
+  if (!REG_P (operands[1]))
+    operands[1] = force_reg (SImode, operands[1]);
   operands[2] = force_reg (SImode, GEN_INT (0x43300000));
   operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503599627370496\", DFmode));
-  operands[4] = assign_stack_temp (DFmode, GET_MODE_SIZE (DFmode), 0);
+  operands[4] = rs6000_allocate_stack_temp (DFmode, true, false);
   operands[5] = gen_reg_rtx (DFmode);
 }")
 
 (define_insn_and_split "*floatunssidf2_internal"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=&f")
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=&d")
        (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
    (use (match_operand:SI 2 "gpc_reg_operand" "r"))
-   (use (match_operand:DF 3 "gpc_reg_operand" "f"))
+   (use (match_operand:DF 3 "gpc_reg_operand" "d"))
    (clobber (match_operand:DF 4 "offsettable_mem_operand" "=o"))
-   (clobber (match_operand:DF 5 "gpc_reg_operand" "=&f"))]
-  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+   (clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))]
+  "! TARGET_FCFIDU && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !(TARGET_FCFID && TARGET_POWERPC64)"
   "#"
-  "&& (can_create_pseudo_p () || offsettable_nonstrict_memref_p (operands[4]))"
+  ""
   [(pc)]
   "
 {
   emit_insn (gen_subdf3 (operands[0], operands[5], operands[3]));
   DONE;
 }"
-  [(set_attr "length" "20")])
+  [(set_attr "length" "20")
+   (set_attr "type" "fp")])
 
-(define_expand "fix_truncdfsi2"
-  [(parallel [(set (match_operand:SI 0 "fix_trunc_dest_operand" "")
-                  (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
-             (clobber (match_dup 2))
-             (clobber (match_dup 3))])]
-  "(TARGET_POWER2 || TARGET_POWERPC)
-   && TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)"
+(define_expand "fix_trunc<mode>si2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
+  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && <TARGET_FLOAT>) || <E500_CONVERT>)"
   "
 {
-  if (TARGET_E500_DOUBLE)
+  if (!<E500_CONVERT>)
     {
-     emit_insn (gen_spe_fix_truncdfsi2 (operands[0], operands[1]));
-     DONE;
+      rtx tmp, stack;
+
+      if (TARGET_STFIWX)
+       emit_insn (gen_fix_trunc<mode>si2_stfiwx (operands[0], operands[1]));
+      else
+       {
+         tmp = gen_reg_rtx (DImode);
+         stack = rs6000_allocate_stack_temp (DImode, true, false);
+         emit_insn (gen_fix_trunc<mode>si2_internal (operands[0], operands[1],
+                                                     tmp, stack));
+       }
+      DONE;
     }
-  operands[2] = gen_reg_rtx (DImode);
-  if (TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
-      && gpc_reg_operand(operands[0], GET_MODE (operands[0])))
+}")
+
+; Like the convert to float patterns, this insn must be split before
+; register allocation so that it can allocate the memory slot if it
+; needed
+(define_insn_and_split "fix_trunc<mode>si2_stfiwx"
+  [(set (match_operand:SI 0 "general_operand" "=rm")
+       (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && (<MODE>mode != SFmode || TARGET_SINGLE_FLOAT)
+   && TARGET_STFIWX && can_create_pseudo_p ()"
+  "#"
+  ""
+  [(pc)]
+{
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx tmp = operands[2];
+
+  if (GET_CODE (tmp) == SCRATCH)
+    tmp = gen_reg_rtx (DImode);
+
+  emit_insn (gen_fctiwz_<mode> (tmp, src));
+  if (MEM_P (dest))
     {
-      operands[3] = gen_reg_rtx (DImode);
-      emit_insn (gen_fix_truncdfsi2_mfpgpr (operands[0], operands[1],
-                                           operands[2], operands[3]));
+      dest = rs6000_address_for_fpconvert (dest);
+      emit_insn (gen_stfiwx (dest, tmp));
       DONE;
     }
-  if (TARGET_PPC_GFXOPT)
+  else if (TARGET_MFPGPR && TARGET_POWERPC64)
     {
-      rtx orig_dest = operands[0];
-      if (! memory_operand (orig_dest, GET_MODE (orig_dest)))
-       operands[0] = assign_stack_temp (SImode, GET_MODE_SIZE (SImode), 0);
-      emit_insn (gen_fix_truncdfsi2_internal_gfxopt (operands[0], operands[1],
-                                                    operands[2]));
-      if (operands[0] != orig_dest)
-       emit_move_insn (orig_dest, operands[0]);
+      dest = gen_lowpart (DImode, dest);
+      emit_move_insn (dest, tmp);
       DONE;
     }
-  operands[3] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
-}")
-
-(define_insn_and_split "*fix_truncdfsi2_internal"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-       (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
-   (clobber (match_operand:DI 3 "offsettable_mem_operand" "=o"))]
-  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
+  else
+    {
+      rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+      emit_insn (gen_stfiwx (stack, tmp));
+      emit_move_insn (dest, stack);
+      DONE;
+    }
+}
+  [(set_attr "length" "12")
+   (set_attr "type" "fp")])
+
+(define_insn_and_split "fix_trunc<mode>si2_internal"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r,?r")
+       (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d,<rreg>")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" "=1,d"))
+   (clobber (match_operand:DI 3 "offsettable_mem_operand" "=o,o"))]
+  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_DOUBLE_FLOAT"
   "#"
-  "&& (can_create_pseudo_p () || offsettable_nonstrict_memref_p (operands[3]))"
+  ""
   [(pc)]
   "
 {
   gcc_assert (MEM_P (operands[3]));
   lowword = adjust_address (operands[3], SImode, WORDS_BIG_ENDIAN ? 4 : 0);
 
-  emit_insn (gen_fctiwz (operands[2], operands[1]));
+  emit_insn (gen_fctiwz_<mode> (operands[2], operands[1]));
   emit_move_insn (operands[3], operands[2]);
   emit_move_insn (operands[0], lowword);
   DONE;
 }"
-  [(set_attr "length" "16")])
+  [(set_attr "length" "16")
+   (set_attr "type" "fp")])
 
-(define_insn_and_split "fix_truncdfsi2_internal_gfxopt"
-  [(set (match_operand:SI 0 "memory_operand" "=Z")
-       (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))]
-  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS
-   && TARGET_PPC_GFXOPT"
-  "#"
-  "&& 1"
-  [(pc)]
+(define_expand "fix_trunc<mode>di2"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+   && TARGET_FCFID"
+  "")
+
+(define_insn "*fix_trunc<mode>di2_fctidz"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+    && TARGET_FCFID && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "fctidz %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_expand "fixuns_trunc<mode>si2"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT
+   && ((TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ && TARGET_STFIWX)
+       || <E500_CONVERT>)"
   "
 {
-  emit_insn (gen_fctiwz (operands[2], operands[1]));
-  emit_insn (gen_stfiwx (operands[0], operands[2]));
-  DONE;
-}"
-  [(set_attr "length" "16")])
+  if (!<E500_CONVERT>)
+    {
+      emit_insn (gen_fixuns_trunc<mode>si2_stfiwx (operands[0], operands[1]));
+      DONE;
+    }
+}")
 
-(define_insn_and_split "fix_truncdfsi2_mfpgpr"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-       (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
-   (clobber (match_operand:DI 3 "gpc_reg_operand" "=r"))]
-  "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS"
+(define_insn_and_split "fixuns_trunc<mode>si2_stfiwx"
+  [(set (match_operand:SI 0 "general_operand" "=rm")
+       (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ
+   && TARGET_STFIWX && can_create_pseudo_p ()"
   "#"
-  "&& 1"
-  [(set (match_dup 2) (unspec:DI [(fix:SI (match_dup 1))] UNSPEC_FCTIWZ))
-   (set (match_dup 3) (match_dup 2))
-   (set (match_dup 0) (subreg:SI (match_dup 3) 4))]
   ""
-  [(set_attr "length" "12")])
+  [(pc)]
+{
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx tmp = operands[2];
+
+  if (GET_CODE (tmp) == SCRATCH)
+    tmp = gen_reg_rtx (DImode);
+
+  emit_insn (gen_fctiwuz_<mode> (tmp, src));
+  if (MEM_P (dest))
+    {
+      dest = rs6000_address_for_fpconvert (dest);
+      emit_insn (gen_stfiwx (dest, tmp));
+      DONE;
+    }
+  else if (TARGET_MFPGPR && TARGET_POWERPC64)
+    {
+      dest = gen_lowpart (DImode, dest);
+      emit_move_insn (dest, tmp);
+      DONE;
+    }
+  else
+    {
+      rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+      emit_insn (gen_stfiwx (stack, tmp));
+      emit_move_insn (dest, stack);
+      DONE;
+    }
+}
+  [(set_attr "length" "12")
+   (set_attr "type" "fp")])
+
+(define_expand "fixuns_trunc<mode>di2"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (unsigned_fix:DI (match_operand:SFDF 1 "register_operand" "")))]
+  "TARGET_HARD_FLOAT && (TARGET_FCTIDUZ || VECTOR_UNIT_VSX_P (<MODE>mode))"
+  "")
+
+(define_insn "*fixuns_trunc<mode>di2_fctiduz"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (unsigned_fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+    && TARGET_FCTIDUZ && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "fctiduz %0,%1"
+  [(set_attr "type" "fp")])
 
 ; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
 ; rather than (set (subreg:SI (reg)) (fix:SI ...))
 ; because the first makes it clear that operand 0 is not live
 ; before the instruction.
-(define_insn "fctiwz"
-  [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
-       (unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))]
+(define_insn "fctiwz_<mode>"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (unspec:DI [(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))]
                   UNSPEC_FCTIWZ))]
-  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_DOUBLE_FLOAT"
   "{fcirz|fctiwz} %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "btruncdf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRIZ))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "friz %0,%1"
+(define_insn "fctiwuz_<mode>"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (unspec:DI [(unsigned_fix:SI
+                    (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>"))]
+                  UNSPEC_FCTIWUZ))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ"
+  "fctiwuz %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "btruncsf2"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIZ))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
+;; Only optimize (float (fix x)) -> frz if we are in fast-math mode, since
+;; since the friz instruction does not truncate the value if the floating
+;; point value is < LONG_MIN or > LONG_MAX.
+(define_insn "*friz"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (float:DF (fix:DI (match_operand:DF 1 "gpc_reg_operand" "d"))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_FPRND
+   && !VECTOR_UNIT_VSX_P (DFmode) && flag_unsafe_math_optimizations
+   && !flag_trapping_math && TARGET_FRIZ"
   "friz %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "ceildf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRIP))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "frip %0,%1"
+;; Since FCTIWZ doesn't sign extend the upper bits, we have to do a store and a
+;; load to properly sign extend the value, but at least doing a store, load
+;; into a GPR to sign extend, a store from the GPR and a load back into the FPR
+;; if we have 32-bit memory ops
+(define_insn_and_split "*round32<mode>2_fprs"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d")
+       (float:SFDF
+        (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))))
+   (clobber (match_scratch:DI 2 "=d"))
+   (clobber (match_scratch:DI 3 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && <SI_CONVERT_FP> && TARGET_LFIWAX && TARGET_STFIWX && TARGET_FCFID
+   && can_create_pseudo_p ()"
+  "#"
+  ""
+  [(pc)]
+{
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx tmp1 = operands[2];
+  rtx tmp2 = operands[3];
+  rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+
+  if (GET_CODE (tmp1) == SCRATCH)
+    tmp1 = gen_reg_rtx (DImode);
+  if (GET_CODE (tmp2) == SCRATCH)
+    tmp2 = gen_reg_rtx (DImode);
+
+  emit_insn (gen_fctiwz_<mode> (tmp1, src));
+  emit_insn (gen_stfiwx (stack, tmp1));
+  emit_insn (gen_lfiwax (tmp2, stack));
+  emit_insn (gen_floatdi<mode>2 (dest, tmp2));
+  DONE;
+}
+  [(set_attr "type" "fpload")
+   (set_attr "length" "16")])
+
+(define_insn_and_split "*roundu32<mode>2_fprs"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d")
+       (unsigned_float:SFDF
+        (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))))
+   (clobber (match_scratch:DI 2 "=d"))
+   (clobber (match_scratch:DI 3 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && TARGET_LFIWZX && TARGET_STFIWX && TARGET_FCFIDU
+   && can_create_pseudo_p ()"
+  "#"
+  ""
+  [(pc)]
+{
+  rtx dest = operands[0];
+  rtx src = operands[1];
+  rtx tmp1 = operands[2];
+  rtx tmp2 = operands[3];
+  rtx stack = rs6000_allocate_stack_temp (SImode, false, true);
+
+  if (GET_CODE (tmp1) == SCRATCH)
+    tmp1 = gen_reg_rtx (DImode);
+  if (GET_CODE (tmp2) == SCRATCH)
+    tmp2 = gen_reg_rtx (DImode);
+
+  emit_insn (gen_fctiwuz_<mode> (tmp1, src));
+  emit_insn (gen_stfiwx (stack, tmp1));
+  emit_insn (gen_lfiwzx (tmp2, stack));
+  emit_insn (gen_floatdi<mode>2 (dest, tmp2));
+  DONE;
+}
+  [(set_attr "type" "fpload")
+   (set_attr "length" "16")])
+
+;; No VSX equivalent to fctid
+(define_insn "lrint<mode>di2"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+       (unspec:DI [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+                  UNSPEC_FCTID))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
+  "fctid %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "ceilsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIP))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "frip %0,%1"
-  [(set_attr "type" "fp")])
+(define_expand "btrunc<mode>2"
 [(set (match_operand:SFDF 0 "gpc_reg_operand" "")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")]
+                    UNSPEC_FRIZ))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
+  "")
 
-(define_insn "floordf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRIM))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "frim %0,%1"
+(define_insn "*btrunc<mode>2_fpr"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+                    UNSPEC_FRIZ))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "friz %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "floorsf2"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIM))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "frim %0,%1"
+(define_expand "ceil<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")]
+                    UNSPEC_FRIP))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
+  "")
+
+(define_insn "*ceil<mode>2_fpr"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+                    UNSPEC_FRIP))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "frip %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "rounddf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRIN))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "frin %0,%1"
+(define_expand "floor<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")]
+                    UNSPEC_FRIM))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
+  "")
+
+(define_insn "*floor<mode>2_fpr"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+                    UNSPEC_FRIM))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>
+   && !VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "frim %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn "roundsf2"
-  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-       (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRIN))]
-  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS"
+;; No VSX equivalent to frin
+(define_insn "round<mode>2"
+  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+       (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")]
+                    UNSPEC_FRIN))]
+  "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>"
   "frin %0,%1"
   [(set_attr "type" "fp")])
 
 ; An UNSPEC is used so we don't have to support SImode in FP registers.
 (define_insn "stfiwx"
   [(set (match_operand:SI 0 "memory_operand" "=Z")
-       (unspec:SI [(match_operand:DI 1 "gpc_reg_operand" "f")]
+       (unspec:SI [(match_operand:DI 1 "gpc_reg_operand" "d")]
                   UNSPEC_STFIWX))]
   "TARGET_PPC_GFXOPT"
   "stfiwx %1,%y0"
   [(set_attr "type" "fpstore")])
 
+;; If we don't have a direct conversion to single precision, don't enable this
+;; conversion for 32-bit without fast math, because we don't have the insn to
+;; generate the fixup swizzle to avoid double rounding problems.
 (define_expand "floatsisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
-        (float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
-  "TARGET_HARD_FLOAT && !TARGET_FPRS"
+        (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT
+   && (!TARGET_FPRS
+       || (TARGET_FPRS
+          && ((TARGET_FCFIDS && TARGET_LFIWAX)
+              || (TARGET_DOUBLE_FLOAT && TARGET_FCFID
+                  && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))"
+  "
+{
+  if (!TARGET_FPRS)
+    {
+      if (!REG_P (operands[1]))
+       operands[1] = force_reg (SImode, operands[1]);
+    }
+  else if (TARGET_FCFIDS && TARGET_LFIWAX)
+    {
+      emit_insn (gen_floatsisf2_lfiwax (operands[0], operands[1]));
+      DONE;
+    }
+  else if (TARGET_FCFID && TARGET_LFIWAX)
+    {
+      rtx dfreg = gen_reg_rtx (DFmode);
+      emit_insn (gen_floatsidf2_lfiwax (dfreg, operands[1]));
+      emit_insn (gen_truncdfsf2 (operands[0], dfreg));
+      DONE;
+    }
+  else
+    {
+      rtx dreg = operands[1];
+      if (!REG_P (dreg))
+       dreg = force_reg (SImode, dreg);
+      dreg = convert_to_mode (DImode, dreg, false);
+      emit_insn (gen_floatdisf2 (operands[0], dreg));
+      DONE;
+    }
+}")
+
+(define_expand "floatdidf2"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "")
+       (float:DF (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
   "")
 
-(define_insn "floatdidf2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (float:DF (match_operand:DI 1 "gpc_reg_operand" "!f#r")))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+(define_insn "*floatdidf2_fpr"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "fcfid %0,%1"
   [(set_attr "type" "fp")])
 
-(define_insn_and_split "floatsidf_ppc64_mfpgpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" "=r"))]
-  "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS"
+; Allow the combiner to merge source memory operands to the conversion so that
+; the optimizer/register allocator doesn't try to load the value too early in a
+; GPR and then use store/load to move it to a FPR and suffer from a store-load
+; hit.  We will split after reload to avoid the trip through the GPRs
+
+(define_insn_and_split "*floatdidf2_mem"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (float:DF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS && TARGET_FCFID"
   "#"
-  "&& 1"
-  [(set (match_dup 2) (sign_extend:DI (match_dup 1)))
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (float:DF (match_dup 2)))]
-  "")
+  ""
+  [(set_attr "length" "8")
+   (set_attr "type" "fpload")])
 
-(define_insn_and_split "floatsidf_ppc64"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
-   (clobber (match_operand:DI 2 "offsettable_mem_operand" "=o"))
-   (clobber (match_operand:DI 3 "gpc_reg_operand" "=r"))
-   (clobber (match_operand:DI 4 "gpc_reg_operand" "=f"))]
-  "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "#"
-  "&& 1"
-  [(set (match_dup 3) (sign_extend:DI (match_dup 1)))
-   (set (match_dup 2) (match_dup 3))
-   (set (match_dup 4) (match_dup 2))
-   (set (match_dup 0) (float:DF (match_dup 4)))]
+(define_expand "floatunsdidf2"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "")
+       (unsigned_float:DF
+        (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT && (TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode))"
   "")
 
-(define_insn_and_split "floatunssidf_ppc64"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r")))
-   (clobber (match_operand:DI 2 "offsettable_mem_operand" "=o"))
-   (clobber (match_operand:DI 3 "gpc_reg_operand" "=r"))
-   (clobber (match_operand:DI 4 "gpc_reg_operand" "=f"))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "#"
-  "&& 1"
-  [(set (match_dup 3) (zero_extend:DI (match_dup 1)))
-   (set (match_dup 2) (match_dup 3))
-   (set (match_dup 4) (match_dup 2))
-   (set (match_dup 0) (float:DF (match_dup 4)))]
-  "")
+(define_insn "*floatunsdidf2_fcfidu"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FCFIDU && !VECTOR_UNIT_VSX_P (DFmode)"
+  "fcfidu %0,%1"
+  [(set_attr "type" "fp")
+   (set_attr "length" "4")])
 
-(define_insn "fix_truncdfdi2"
-  [(set (match_operand:DI 0 "gpc_reg_operand" "=!f#r")
-       (fix:DI (match_operand:DF 1 "gpc_reg_operand" "f")))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
-  "fctidz %0,%1"
-  [(set_attr "type" "fp")])
+(define_insn_and_split "*floatunsdidf2_mem"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (unsigned_float:DF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=d"))]
+  "TARGET_HARD_FLOAT && (TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode))"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 1))
+   (set (match_dup 0) (unsigned_float:DF (match_dup 2)))]
+  ""
+  [(set_attr "length" "8")
+   (set_attr "type" "fpload")])
 
 (define_expand "floatdisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
         (float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && (TARGET_FCFIDS || TARGET_POWERPC64 || flag_unsafe_math_optimizations)"
   "
 {
-  rtx val = operands[1];
-  if (!flag_unsafe_math_optimizations)
+  if (!TARGET_FCFIDS)
     {
-      rtx label = gen_label_rtx ();
-      val = gen_reg_rtx (DImode);
-      emit_insn (gen_floatdisf2_internal2 (val, operands[1], label));
-      emit_label (label);
+      rtx val = operands[1];
+      if (!flag_unsafe_math_optimizations)
+       {
+         rtx label = gen_label_rtx ();
+         val = gen_reg_rtx (DImode);
+         emit_insn (gen_floatdisf2_internal2 (val, operands[1], label));
+         emit_label (label);
+       }
+      emit_insn (gen_floatdisf2_internal1 (operands[0], val));
+      DONE;
     }
-  emit_insn (gen_floatdisf2_internal1 (operands[0], val));
-  DONE;
 }")
 
+(define_insn "floatdisf2_fcfids"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+       (float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS"
+  "fcfids %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_insn_and_split "*floatdisf2_mem"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+       (float:SF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=f"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_move_insn (operands[2], operands[1]);
+  emit_insn (gen_floatdisf2_fcfids (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")])
+
 ;; This is not IEEE compliant if rounding mode is "round to nearest".
 ;; If the DI->DF conversion is inexact, then it's possible to suffer
 ;; from double rounding.
+;; Instead of creating a new cpu type for two FP operations, just use fp
 (define_insn_and_split "floatdisf2_internal1"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
-        (float:SF (match_operand:DI 1 "gpc_reg_operand" "!f#r")))
-   (clobber (match_scratch:DF 2 "=f"))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+        (float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))
+   (clobber (match_scratch:DF 2 "=d"))]
+  "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "#"
   "&& reload_completed"
   [(set (match_dup 2)
         (float:DF (match_dup 1)))
    (set (match_dup 0)
         (float_truncate:SF (match_dup 2)))]
-  "")
+  ""
+  [(set_attr "length" "8")
+   (set_attr "type" "fp")])
 
 ;; Twiddles bits to avoid double rounding.
 ;; Bits that might be truncated when converting to DFmode are replaced
                           (label_ref (match_operand:DI 2 "" ""))
                           (pc)))
    (set (match_dup 0) (match_dup 1))]
-  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+  "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "
 {
   operands[3] = gen_reg_rtx (DImode);
   operands[4] = gen_reg_rtx (CCUNSmode);
 }")
+
+(define_expand "floatunsdisf2"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "")
+        (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+  "")
+
+(define_insn "floatunsdisf2_fcfidus"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+        (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+  "fcfidus %0,%1"
+  [(set_attr "type" "fp")])
+
+(define_insn_and_split "*floatunsdisf2_mem"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+       (unsigned_float:SF (match_operand:DI 1 "memory_operand" "m")))
+   (clobber (match_scratch:DI 2 "=f"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+  "#"
+  "&& reload_completed"
+  [(pc)]
+  "
+{
+  emit_move_insn (operands[2], operands[1]);
+  emit_insn (gen_floatunsdisf2_fcfidus (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "8")
+   (set_attr "type" "fpload")])
 \f
 ;; Define the DImode operations that can be done in a small number
 ;; of instructions.  The & constraints are to prevent the register
 \f
 ;; PowerPC64 DImode operations.
 
-(define_insn_and_split "absdi2"
+(define_expand "absdi2"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (abs:DI (match_operand:DI 1 "gpc_reg_operand" "")))]
+  "TARGET_POWERPC64"
+  "
+{
+  if (TARGET_ISEL)
+    emit_insn (gen_absdi2_isel (operands[0], operands[1]));
+  else
+    emit_insn (gen_absdi2_internal (operands[0], operands[1]));
+  DONE;
+}")
+
+(define_insn_and_split "absdi2_internal"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
         (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))
    (clobber (match_scratch:DI 2 "=&r,&r"))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && !TARGET_ISEL"
   "#"
   "&& reload_completed"
   [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63)))
   [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r")
         (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0"))))
    (clobber (match_scratch:DI 2 "=&r,&r"))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && !TARGET_ISEL"
   "#"
   "&& reload_completed"
   [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63)))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (mult:DI (match_operand:DI 1 "gpc_reg_operand" "")
                             (match_operand:DI 2 "gpc_reg_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
                               (match_operand:DI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
                               (match_operand:DI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:DI
                     (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
                                (match_operand:DI 2 "reg_or_cint_operand" ""))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:DI
                     (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
                                (match_operand:DI 2 "reg_or_cint_operand" ""))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI
                     (subreg:QI
                      (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI
                     (subreg:QI
                      (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI
                     (subreg:HI
                      (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI
                     (subreg:HI
                      (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI
                     (subreg:SI
                      (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (zero_extend:DI
                     (subreg:SI
                      (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "")
                            (match_operand:SI 2 "const_int_operand" ""))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
                                 (match_operand:SI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
    (set_attr "length" "4,4,8,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "")
                                 (match_operand:SI 2 "reg_or_cint_operand" ""))
                    (const_int 0)))
                    (const_int 0)))]
   "")
 
-(define_insn "anddi3"
+(define_expand "anddi3"
+  [(parallel
+    [(set (match_operand:DI 0 "gpc_reg_operand" "")
+         (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
+                 (match_operand:DI 2 "and64_2_operand" "")))
+     (clobber (match_scratch:CC 3 ""))])]
+  "TARGET_POWERPC64"
+  "")
+
+(define_insn "anddi3_mc"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r")
        (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r")
                (match_operand:DI 2 "and64_2_operand" "?r,S,T,K,J,t")))
    (clobber (match_scratch:CC 3 "=X,X,X,x,x,X"))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && rs6000_gen_cell_microcode"
   "@
    and %0,%1,%2
    rldic%B2 %0,%1,0,%S2
    andi. %0,%1,%b2
    andis. %0,%1,%u2
    #"
-  [(set_attr "type" "*,*,*,compare,compare,*")
+  [(set_attr "type" "*,*,*,fast_compare,fast_compare,*")
    (set_attr "length" "4,4,4,4,4,8")])
 
+(define_insn "anddi3_nomc"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r")
+       (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r")
+               (match_operand:DI 2 "and64_2_operand" "?r,S,T,t")))
+   (clobber (match_scratch:CC 3 "=X,X,X,X"))]
+  "TARGET_POWERPC64 && !rs6000_gen_cell_microcode"
+  "@
+   and %0,%1,%2
+   rldic%B2 %0,%1,0,%S2
+   rlwinm %0,%1,0,%m2,%M2
+   #"
+  [(set_attr "length" "4,4,4,8")])
+
 (define_split
   [(set (match_operand:DI 0 "gpc_reg_operand" "")
        (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
   build_mask64_2_operands (operands[2], &operands[4]);
 })
 
-(define_insn "*anddi3_internal2"
+(define_insn "*anddi3_internal2_mc"
   [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x,x,?y,?y,?y,??y,??y,?y")
        (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r,r,r")
                            (match_operand:DI 2 "and64_2_operand" "r,S,T,K,J,t,r,S,T,K,J,t"))
                    (const_int 0)))
    (clobber (match_scratch:DI 3 "=r,r,r,r,r,r,r,r,r,r,r,r"))
    (clobber (match_scratch:CC 4 "=X,X,X,X,X,X,X,X,X,x,x,X"))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_gen_cell_microcode"
   "@
    and. %3,%1,%2
    rldic%B2. %3,%1,0,%S2
    #
    #
    #"
-  [(set_attr "type" "compare,compare,delayed_compare,compare,compare,compare,compare,compare,compare,compare,compare,compare")
+  [(set_attr "type" "fast_compare,compare,delayed_compare,fast_compare,\
+                    fast_compare,compare,compare,compare,compare,compare,\
+                    compare,compare")
    (set_attr "length" "4,4,4,4,4,8,8,8,8,8,8,12")])
 
 (define_split
   build_mask64_2_operands (operands[2], &operands[5]);
 }")
 
-(define_insn "*anddi3_internal3"
+(define_insn "*anddi3_internal3_mc"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,x,x,?y,?y,?y,??y,??y,?y")
        (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r,r,r")
                            (match_operand:DI 2 "and64_2_operand" "r,S,T,K,J,t,r,S,T,K,J,t"))
    (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,r,r,r,r")
        (and:DI (match_dup 1) (match_dup 2)))
    (clobber (match_scratch:CC 4 "=X,X,X,X,X,X,X,X,X,x,x,X"))]
-  "TARGET_64BIT"
+  "TARGET_64BIT && rs6000_gen_cell_microcode"
   "@
    and. %0,%1,%2
    rldic%B2. %0,%1,0,%S2
    #
    #
    #"
-  [(set_attr "type" "compare,compare,delayed_compare,compare,compare,compare,compare,compare,compare,compare,compare,compare")
+  [(set_attr "type" "fast_compare,compare,delayed_compare,fast_compare,\
+                    fast_compare,compare,compare,compare,compare,compare,\
+                    compare,compare")
    (set_attr "length" "4,4,4,4,4,8,8,8,8,8,8,12")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "")
                            (match_operand:DI 2 "and64_2_operand" ""))
                    (const_int 0)))
   "@
    %q4. %3,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:DI 4 "boolean_operator"
         [(match_operand:DI 1 "gpc_reg_operand" "")
          (match_operand:DI 2 "gpc_reg_operand" "")])
 
 (define_insn "*booldi3_internal3"
   [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
-       (compare:CC (match_operator:DI 4 "boolean_operator"
+       (compare:CC (match_operator:DI 4 "boolean_or_operator"
         [(match_operand:DI 1 "gpc_reg_operand" "%r,r")
          (match_operand:DI 2 "gpc_reg_operand" "r,r")])
         (const_int 0)))
   "@
    %q4. %0,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:DI 4 "boolean_operator"
         [(match_operand:DI 1 "gpc_reg_operand" "")
          (match_operand:DI 2 "gpc_reg_operand" "")])
   "@
    %q4. %3,%2,%1
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:DI 4 "boolean_operator"
         [(not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
          (match_operand:DI 2 "gpc_reg_operand" "")])
   "@
    %q4. %0,%2,%1
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:DI 4 "boolean_operator"
         [(not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
          (match_operand:DI 2 "gpc_reg_operand" "")])
   "@
    %q4. %3,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:DI 4 "boolean_operator"
         [(not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
          (not:DI (match_operand:DI 2 "gpc_reg_operand" ""))])
   "@
    %q4. %0,%1,%2
    #"
-  [(set_attr "type" "compare")
+  [(set_attr "type" "fast_compare,compare")
    (set_attr "length" "4,8")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operator:DI 4 "boolean_operator"
         [(not:DI (match_operand:DI 1 "gpc_reg_operand" ""))
          (not:DI (match_operand:DI 2 "gpc_reg_operand" ""))])
        (compare:CC (match_dup 0)
                    (const_int 0)))]
   "")
+
+(define_expand "smindi3"
+  [(match_operand:DI 0 "gpc_reg_operand" "")
+   (match_operand:DI 1 "gpc_reg_operand" "")
+   (match_operand:DI 2 "gpc_reg_operand" "")]
+  "TARGET_ISEL64"
+  "
+{
+  rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]);
+  DONE;
+}")
+
+(define_expand "smaxdi3"
+  [(match_operand:DI 0 "gpc_reg_operand" "")
+   (match_operand:DI 1 "gpc_reg_operand" "")
+   (match_operand:DI 2 "gpc_reg_operand" "")]
+  "TARGET_ISEL64"
+  "
+{
+  rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]);
+  DONE;
+}")
+
+(define_expand "umindi3"
+  [(match_operand:DI 0 "gpc_reg_operand" "")
+   (match_operand:DI 1 "gpc_reg_operand" "")
+   (match_operand:DI 2 "gpc_reg_operand" "")]
+  "TARGET_ISEL64"
+  "
+{
+  rs6000_emit_minmax (operands[0], UMIN, operands[1], operands[2]);
+  DONE;
+}")
+
+(define_expand "umaxdi3"
+  [(match_operand:DI 0 "gpc_reg_operand" "")
+   (match_operand:DI 1 "gpc_reg_operand" "")
+   (match_operand:DI 2 "gpc_reg_operand" "")]
+  "TARGET_ISEL64"
+  "
+{
+  rs6000_emit_minmax (operands[0], UMAX, operands[1], operands[2]);
+  DONE;
+}")
+
 \f
 ;; Now define ways of moving data around.
 
 (define_insn "*movsi_internal1"
   [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
        (match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0"))]
-  "gpc_reg_operand (operands[0], SImode)
-   || gpc_reg_operand (operands[1], SImode)"
+  "!TARGET_SINGLE_FPU &&
+   (gpc_reg_operand (operands[0], SImode) || gpc_reg_operand (operands[1], SImode))"
   "@
    mr %0,%1
    {cal|la} %0,%a1
   [(set_attr "type" "*,*,load,store,*,*,*,*,mfjmpr,*,mtjmpr,*,*")
    (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4,4")])
 
+(define_insn "*movsi_internal1_single"
+  [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h,m,*f")
+        (match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0,f,m"))]
+  "TARGET_SINGLE_FPU &&
+   (gpc_reg_operand (operands[0], SImode) || gpc_reg_operand (operands[1], SImode))"
+  "@
+   mr %0,%1
+   {cal|la} %0,%a1
+   {l%U1%X1|lwz%U1%X1} %0,%1
+   {st%U0%X0|stw%U0%X0} %1,%0
+   {lil|li} %0,%1
+   {liu|lis} %0,%v1
+   #
+   {cal|la} %0,%a1
+   mf%1 %0
+   mt%0 %1
+   mt%0 %1
+   mt%0 %1
+   {cror 0,0,0|nop}
+   stfs%U0%X0 %1, %0
+   lfs%U1%X1 %0, %1"
+  [(set_attr "type" "*,*,load,store,*,*,*,*,mfjmpr,*,mtjmpr,*,*,*,*")
+   (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4,4,4,4")])
+
 ;; Split a load of a large constant into the appropriate two-insn
 ;; sequence.
 
    (set_attr "length" "4,4,8")])
 
 (define_split
-  [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC (match_operand:P 1 "gpc_reg_operand" "")
                    (const_int 0)))
    (set (match_operand:P 0 "gpc_reg_operand" "") (match_dup 1))]
        (match_operand:SF 1 "input_operand" "r,m,r,f,m,f,r,r,h,0,G,Fn"))]
   "(gpc_reg_operand (operands[0], SFmode)
    || gpc_reg_operand (operands[1], SFmode))
-   && (TARGET_HARD_FLOAT && TARGET_FPRS)"
+   && (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT)"
   "@
    mr %0,%1
    {l%U1%X1|lwz%U1%X1} %0,%1
 ;; The "??" is a kludge until we can figure out a more reasonable way
 ;; of handling these non-offsettable values.
 (define_insn "*movdf_hardfloat32"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,f,f,m,!r,!r,!r")
-       (match_operand:DF 1 "input_operand" "r,m,r,f,m,f,G,H,F"))]
-  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,!r,!r,!r")
+       (match_operand:DF 1 "input_operand" "r,m,r,ws,wa,Z,Z,ws,wa,d,m,d,j,G,H,F"))]
+  "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
    && (gpc_reg_operand (operands[0], DFmode)
        || gpc_reg_operand (operands[1], DFmode))"
   "*
     default:
       gcc_unreachable ();
     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 (rs6000_offsettable_memref_p (operands[1])
-         || (GET_CODE (operands[1]) == MEM
-             && (GET_CODE (XEXP (operands[1], 0)) == LO_SUM
-                 || GET_CODE (XEXP (operands[1], 0)) == PRE_INC
-                 || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC
-                 || GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY)))
-       {
-         /* 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%X1|lwz%U1%X1} %0,%1\;{l|lwz} %L0,%L1\";
-       }
-      else
-       {
-         rtx addreg;
-
-         addreg = find_addr_reg (XEXP (operands[1], 0));
-         if (refers_to_regno_p (REGNO (operands[0]),
-                                REGNO (operands[0]) + 1,
-                                operands[1], 0))
-           {
-             output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
-             output_asm_insn (\"{l%X1|lwz%X1} %L0,%1\", operands);
-             output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
-             return \"{l%X1|lwz%X1} %0,%1\";
-           }
-         else
-           {
-             output_asm_insn (\"{l%X1|lwz%X1} %0,%1\", operands);
-             output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
-             output_asm_insn (\"{l%X1|lwz%X1} %L0,%1\", operands);
-             output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
-             return \"\";
-           }
-       }
     case 2:
-      if (rs6000_offsettable_memref_p (operands[0])
-         || (GET_CODE (operands[0]) == MEM
-             && (GET_CODE (XEXP (operands[0], 0)) == LO_SUM
-                 || GET_CODE (XEXP (operands[0], 0)) == PRE_INC
-                 || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC
-                 || GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)))
-       return \"{st%U0%X0|stw%U0%X0} %1,%0\;{st|stw} %L1,%L0\";
-      else
-       {
-         rtx addreg;
-
-         addreg = find_addr_reg (XEXP (operands[0], 0));
-         output_asm_insn (\"{st%X0|stw%X0} %1,%0\", operands);
-         output_asm_insn (\"{cal|la} %0,4(%0)\", &addreg);
-         output_asm_insn (\"{st%X0|stw%X0} %L1,%0\", operands);
-         output_asm_insn (\"{cal|la} %0,-4(%0)\", &addreg);
-         return \"\";
-       }
+      return \"#\";
     case 3:
-      return \"fmr %0,%1\";
     case 4:
-      return \"lfd%U1%X1 %0,%1\";
+      return \"xxlor %x0,%x1,%x1\";
     case 5:
-      return \"stfd%U0%X0 %1,%0\";
     case 6:
+      return \"lxsd%U1x %x0,%y1\";
     case 7:
     case 8:
+      return \"stxsd%U0x %x1,%y0\";
+    case 9:
+      return \"fmr %0,%1\";
+    case 10:
+      return \"lfd%U1%X1 %0,%1\";
+    case 11:
+      return \"stfd%U0%X0 %1,%0\";
+    case 12:
+      return \"xxlxor %x0,%x0,%x0\";
+    case 13:
+    case 14:
+    case 15:
       return \"#\";
     }
 }"
-  [(set_attr "type" "two,load,store,fp,fpload,fpstore,*,*,*")
-   (set_attr "length" "8,16,16,4,4,4,8,12,16")])
+  [(set_attr "type" "two,load,store,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,*,*,*")
+   (set_attr "length" "8,16,16,4,4,4,4,4,4,4,4,4,4,8,12,16")])
 
 (define_insn "*movdf_softfloat32"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
        (match_operand:DF 1 "input_operand" "r,m,r,G,H,F"))]
-  "! TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || TARGET_E500_SINGLE)
+  "! TARGET_POWERPC64 
+   && ((TARGET_FPRS && TARGET_SINGLE_FLOAT) 
+       || TARGET_SOFT_FLOAT || TARGET_E500_SINGLE)
    && (gpc_reg_operand (operands[0], DFmode)
        || gpc_reg_operand (operands[1], DFmode))"
-  "*
-{
-  switch (which_alternative)
-    {
-    default:
-      gcc_unreachable ();
-    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%X1|lwz%U1%X1} %0,%1\;{l|lwz} %L0,%L1\";
-    case 2:
-      return \"{st%U0%X0|stw%U0%X0} %1,%0\;{st|stw} %L1,%L0\";
-    case 3:
-    case 4:
-    case 5:
-      return \"#\";
-    }
-}"
+  "#"
   [(set_attr "type" "two,load,store,*,*,*")
    (set_attr "length" "8,8,8,8,12,16")])
 
+;; Reload patterns to support gpr load/store with misaligned mem.
+(define_expand "reload_di_store"
+  [(parallel [(match_operand 0 "memory_operand" "=m")
+              (match_operand 1 "gpc_reg_operand" "r")
+              (match_operand:DI 2 "register_operand" "=&b")])]
+  "TARGET_POWERPC64"
+{
+  rs6000_secondary_reload_ppc64 (operands[1], operands[0], operands[2], true);
+  DONE;
+})
+
+(define_expand "reload_di_load"
+  [(parallel [(match_operand 0 "gpc_reg_operand" "=r")
+              (match_operand 1 "memory_operand" "m")
+              (match_operand:DI 2 "register_operand" "=b")])]
+  "TARGET_POWERPC64"
+{
+  rs6000_secondary_reload_ppc64 (operands[0], operands[1], operands[2], false);
+  DONE;
+})
+
 ; ld/std require word-aligned displacements -> 'Y' constraint.
 ; List Y->r and r->Y before r->r for reload.
 (define_insn "*movdf_hardfloat64_mfpgpr"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,f,f,m,*c*l,!r,*h,!r,!r,!r,r,f")
-       (match_operand:DF 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F,f,r"))]
-  "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,*c*l,!r,*h,!r,!r,!r,r,d")
+       (match_operand:DF 1 "input_operand" "r,Y,r,ws,?wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F,d,r"))]
+  "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_DOUBLE_FLOAT
    && (gpc_reg_operand (operands[0], DFmode)
        || gpc_reg_operand (operands[1], DFmode))"
   "@
    std%U0%X0 %1,%0
    ld%U1%X1 %0,%1
    mr %0,%1
+   xxlor %x0,%x1,%x1
+   xxlor %x0,%x1,%x1
+   lxsd%U1x %x0,%y1
+   lxsd%U1x %x0,%y1
+   stxsd%U0x %x1,%y0
+   stxsd%U0x %x1,%y0
    fmr %0,%1
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0
+   xxlxor %x0,%x0,%x0
    mt%0 %1
    mf%1 %0
    {cror 0,0,0|nop}
    #
    mftgpr %0,%1
    mffgpr %0,%1"
-  [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
-   (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
+  [(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
+   (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
 
 ; ld/std require word-aligned displacements -> 'Y' constraint.
 ; List Y->r and r->Y before r->r for reload.
 (define_insn "*movdf_hardfloat64"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,f,f,m,*c*l,!r,*h,!r,!r,!r")
-       (match_operand:DF 1 "input_operand" "r,Y,r,f,m,f,r,h,0,G,H,F"))]
-  "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,*c*l,!r,*h,!r,!r,!r")
+       (match_operand:DF 1 "input_operand" "r,Y,r,ws,wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F"))]
+  "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS 
+   && TARGET_DOUBLE_FLOAT
    && (gpc_reg_operand (operands[0], DFmode)
        || gpc_reg_operand (operands[1], DFmode))"
   "@
    std%U0%X0 %1,%0
    ld%U1%X1 %0,%1
    mr %0,%1
+   xxlor %x0,%x1,%x1
+   xxlor %x0,%x1,%x1
+   lxsd%U1x %x0,%y1
+   lxsd%U1x %x0,%y1
+   stxsd%U0x %x1,%y0
+   stxsd%U0x %x1,%y0
    fmr %0,%1
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0
+   xxlxor %x0,%x0,%x0
    mt%0 %1
    mf%1 %0
    {cror 0,0,0|nop}
    #
    #
    #"
-  [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*")
-   (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16")])
+  [(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,mtjmpr,mfjmpr,*,*,*,*")
+   (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16")])
 
 (define_insn "*movdf_softfloat64"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,Y,r,cl,r,r,r,r,*h")
 ; otherwise reload, given m->f, will try to pick f->f and reload it,
 ; which doesn't make progress.  Likewise r->Y must be before r->r.
 (define_insn_and_split "*movtf_internal"
-  [(set (match_operand:TF 0 "nonimmediate_operand" "=o,f,f,r,Y,r")
-       (match_operand:TF 1 "input_operand"         "f,o,f,YGHF,r,r"))]
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=o,d,d,r,Y,r")
+       (match_operand:TF 1 "input_operand"         "d,o,d,YGHF,r,r"))]
   "!TARGET_IEEEQUAD
    && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
    && (gpc_reg_operand (operands[0], TFmode)
                   (float_extend:TF (match_operand:DF 1 "input_operand" "")))
              (use (match_dup 2))])]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && TARGET_LONG_DOUBLE_128"
 {
   operands[2] = CONST0_RTX (DFmode);
   /* Generate GOT reference early for SVR4 PIC.  */
 })
 
 (define_insn_and_split "*extenddftf2_internal"
-  [(set (match_operand:TF 0 "nonimmediate_operand" "=o,f,&f,r")
-       (float_extend:TF (match_operand:DF 1 "input_operand" "fr,mf,mf,rmGHF")))
-   (use (match_operand:DF 2 "zero_reg_mem_operand" "rf,m,f,n"))]
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=o,d,&d,r")
+       (float_extend:TF (match_operand:DF 1 "input_operand" "dr,md,md,rmGHF")))
+   (use (match_operand:DF 2 "zero_reg_mem_operand" "rd,m,d,n"))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && TARGET_LONG_DOUBLE_128"
   "#"
   "&& reload_completed"
   [(pc)]
   "")
 
 (define_insn_and_split "trunctfdf2_internal1"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f,?f")
-       (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "0,f")))]
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d")
+       (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "0,d")))]
   "!TARGET_IEEEQUAD && !TARGET_XL_COMPAT
    && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
   "@
   [(set_attr "type" "fp")])
 
 (define_insn "trunctfdf2_internal2"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "f")))]
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "d")))]
   "!TARGET_IEEEQUAD && TARGET_XL_COMPAT
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && TARGET_LONG_DOUBLE_128"
   "fadd %0,%1,%L1"
-  [(set_attr "type" "fp")])
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_addsub_d")])
 
 (define_expand "trunctfsf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
 
 (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"))]
+       (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "d")))
+   (clobber (match_scratch:DF 2 "=d"))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT 
+   && TARGET_LONG_DOUBLE_128"
   "#"
   "&& reload_completed"
   [(set (match_dup 2)
 ; fadd, but rounding towards zero.
 ; This is probably not the optimal code sequence.
 (define_insn "fix_trunc_helper"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-       (unspec:DF [(match_operand:TF 1 "gpc_reg_operand" "f")]
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+       (unspec:DF [(match_operand:TF 1 "gpc_reg_operand" "d")]
                   UNSPEC_FIX_TRUNC_TF))
-   (clobber (match_operand:DF 2 "gpc_reg_operand" "=&f"))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS"
+   (clobber (match_operand:DF 2 "gpc_reg_operand" "=&d"))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
   "mffs %2\n\tmtfsb1 31\n\tmtfsb0 30\n\tfadd %0,%1,%L1\n\tmtfsf 1,%2"
   [(set_attr "type" "fp")
    (set_attr "length" "20")])
 
 (define_insn_and_split "*fix_trunctfsi2_internal"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-        (fix:SI (match_operand:TF 1 "gpc_reg_operand" "f")))
-   (clobber (match_operand:DF 2 "gpc_reg_operand" "=f"))
-   (clobber (match_operand:DF 3 "gpc_reg_operand" "=&f"))
-   (clobber (match_operand:DI 4 "gpc_reg_operand" "=f"))
+        (fix:SI (match_operand:TF 1 "gpc_reg_operand" "d")))
+   (clobber (match_operand:DF 2 "gpc_reg_operand" "=d"))
+   (clobber (match_operand:DF 3 "gpc_reg_operand" "=&d"))
+   (clobber (match_operand:DI 4 "gpc_reg_operand" "=d"))
    (clobber (match_operand:DI 5 "offsettable_mem_operand" "=o"))]
   "!TARGET_IEEEQUAD
    && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
   "#"
-  "&& (can_create_pseudo_p () || offsettable_nonstrict_memref_p (operands[5]))"
+  ""
   [(pc)]
 {
   rtx lowword;
   gcc_assert (MEM_P (operands[5]));
   lowword = adjust_address (operands[5], SImode, WORDS_BIG_ENDIAN ? 4 : 0);
 
-  emit_insn (gen_fctiwz (operands[4], operands[2]));
+  emit_insn (gen_fctiwz_df (operands[4], operands[2]));
   emit_move_insn (operands[5], operands[4]);
   emit_move_insn (operands[0], lowword);
   DONE;
   "")
 
 (define_insn "negtf2_internal"
-  [(set (match_operand:TF 0 "gpc_reg_operand" "=f")
-       (neg:TF (match_operand:TF 1 "gpc_reg_operand" "f")))]
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=d")
+       (neg:TF (match_operand:TF 1 "gpc_reg_operand" "d")))]
   "!TARGET_IEEEQUAD
    && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
   "*
   rtx label = gen_label_rtx ();
   if (TARGET_E500_DOUBLE)
     {
-      if (flag_unsafe_math_optimizations)
+      if (flag_finite_math_only && !flag_trapping_math)
        emit_insn (gen_spe_abstf2_tst (operands[0], operands[1], label));
       else
        emit_insn (gen_spe_abstf2_cmp (operands[0], operands[1], label));
                           (pc)))
    (set (match_dup 6) (neg:DF (match_dup 6)))]
   "!TARGET_IEEEQUAD
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
+   && TARGET_LONG_DOUBLE_128"
   "
 {
   const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
 ; 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 "rs6000_nonimmediate_operand" "=o<>,r,r,*f,*f,m,r")
-       (match_operand:DI 1 "input_operand" "r,r,m,f,m,f,IJKnGHF"))]
+  [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*d,*d,m,r,?wa")
+       (match_operand:DI 1 "input_operand" "r,r,m,d,m,d,IJKnGHF,O"))]
   "! TARGET_POWERPC64
    && (gpc_reg_operand (operands[0], DImode)
        || gpc_reg_operand (operands[1], DImode))"
    fmr %0,%1
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0
-   #"
-  [(set_attr "type" "load,*,store,fp,fpload,fpstore,*")])
+   #
+   xxlxor %x0,%x0,%x0"
+  [(set_attr "type" "load,*,store,fp,fpload,fpstore,*,vecsimple")])
 
 (define_split
   [(set (match_operand:DI 0 "gpc_reg_operand" "")
        (match_operand:DI 1 "const_int_operand" ""))]
-  "! TARGET_POWERPC64 && reload_completed"
+  "! TARGET_POWERPC64 && reload_completed
+   && gpr_or_gpr_p (operands[0], operands[1])"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 3) (match_dup 1))]
   "
 }")
 
 (define_split
-  [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "")
-        (match_operand:DI 1 "input_operand" ""))]
+  [(set (match_operand:DIFD 0 "rs6000_nonimmediate_operand" "")
+        (match_operand:DIFD 1 "input_operand" ""))]
   "reload_completed && !TARGET_POWERPC64
    && gpr_or_gpr_p (operands[0], operands[1])"
   [(pc)]
 { rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
 
 (define_insn "*movdi_mfpgpr"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*f,*f,m,r,*h,*h,r,*f")
-       (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,f,m,f,*h,r,0,*f,r"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*d,*d,m,r,*h,*h,r,*d")
+       (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,d,m,d,*h,r,0,*d,r"))]
   "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
    && (gpc_reg_operand (operands[0], DImode)
        || gpc_reg_operand (operands[1], DImode))"
    li %0,%1
    lis %0,%v1
    #
-   {cal|la} %0,%a1
+   la %0,%a1
    fmr %0,%1
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0
    (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4,4")])
 
 (define_insn "*movdi_internal64"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*f,*f,m,r,*h,*h")
-       (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,f,m,f,*h,r,0"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*d,*d,m,r,*h,*h,?wa")
+       (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,d,m,d,*h,r,0,O"))]
   "TARGET_POWERPC64 && (!TARGET_MFPGPR || !TARGET_HARD_FLOAT || !TARGET_FPRS)
    && (gpc_reg_operand (operands[0], DImode)
        || gpc_reg_operand (operands[1], DImode))"
    li %0,%1
    lis %0,%v1
    #
-   {cal|la} %0,%a1
+   la %0,%a1
    fmr %0,%1
    lfd%U1%X1 %0,%1
    stfd%U0%X0 %1,%0
    mf%1 %0
    mt%0 %1
-   {cror 0,0,0|nop}"
-  [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*")
-   (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")])
+   {cror 0,0,0|nop}
+   xxlxor %x0,%x0,%x0"
+  [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,vecsimple")
+   (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4")])
 
 ;; immediate value valid for a single instruction hiding in a const_double
 (define_insn ""
       return \"#\";
     }
 }"
-  [(set_attr "type" "store_ux,store_ux,*,load_ux,load_ux,*")])
+  [(set_attr "type" "store_ux,store_ux,*,load_ux,load_ux,*")
+   (set (attr "cell_micro") (if_then_else (eq (symbol_ref "TARGET_STRING") (const_int 1))
+                                         (const_string "always")
+                                         (const_string "conditional")))])
 
 (define_insn "*movti_ppc64"
   [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o<>,r")
        (match_operand:TI 1 "input_operand" "r,r,m"))]
-  "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
-   || gpc_reg_operand (operands[1], TImode))"
+  "(TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
+    || gpc_reg_operand (operands[1], TImode)))
+   && VECTOR_MEM_NONE_P (TImode)"
   "#"
-  [(set_attr "type" "*,load,store")])
+  [(set_attr "type" "*,store,load")])
 
 (define_split
   [(set (match_operand:TI 0 "gpc_reg_operand" "")
        (match_operand:TI 1 "const_double_operand" ""))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && VECTOR_MEM_NONE_P (TImode)"
   [(set (match_dup 2) (match_dup 4))
    (set (match_dup 3) (match_dup 5))]
   "
 (define_split
   [(set (match_operand:TI 0 "nonimmediate_operand" "")
         (match_operand:TI 1 "input_operand" ""))]
-  "reload_completed
+  "reload_completed && VECTOR_MEM_NONE_P (TImode)
    && gpr_or_gpr_p (operands[0], operands[1])"
   [(pc)]
 { rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
          (match_operand:SI 10 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 9"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi7"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 9 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 8"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi6"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 8 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 7"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi5"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 7 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 6"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi4"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 6 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 5"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi3"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 5 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 4"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi8_power"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 10 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 9"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi7_power"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 9 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 8"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi6_power"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 8 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 7"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi5_power"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 7 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 6"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi4_power"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 6 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 5"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*stmsi3_power"
   [(match_parallel 0 "store_multiple_operation"
          (match_operand:SI 5 "gpc_reg_operand" "r"))])]
   "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 4"
   "{stsi|stswi} %2,%1,%O0"
-  [(set_attr "type" "store_ux")])
+  [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")])
 \f
 (define_expand "setmemsi"
   [(parallel [(set (match_operand:BLK 0 "" "")
    && REGNO (operands[4]) == 5"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 (define_insn ""
    && REGNO (operands[4]) == 5"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 ;; Move up to 24 bytes at a time.  The fixed registers are needed because the
    && REGNO (operands[4]) == 5"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 (define_insn ""
    && REGNO (operands[4]) == 5"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 ;; Move up to 16 bytes at a time, using 4 fixed registers to avoid spill
    && REGNO (operands[4]) == 5"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 (define_insn ""
    && REGNO (operands[4]) == 5"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 ;; Move up to 8 bytes at a time.
    && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 (define_insn ""
    && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 ;; Move up to 4 bytes at a time.
    && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 
 (define_insn ""
    && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4"
   "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2"
   [(set_attr "type" "store_ux")
+   (set_attr "cell_micro" "always")
    (set_attr "length" "8")])
 \f
 ;; Define insns that do load or store with update.  Some of these we can
                         (match_operand:DI 2 "reg_or_aligned_short_operand" "r,I"))))
    (set (match_operand:DI 0 "gpc_reg_operand" "=b,b")
        (plus:DI (match_dup 1) (match_dup 2)))]
-  "TARGET_POWERPC64 && TARGET_UPDATE"
+  "TARGET_POWERPC64 && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (DImode)
+       || !gpc_reg_operand (operands[2], DImode))"
   "@
    ldux %3,%0,%2
    ldu %3,%2(%0)"
        (match_operand:DI 3 "gpc_reg_operand" "r,r"))
    (set (match_operand:P 0 "gpc_reg_operand" "=b,b")
        (plus:P (match_dup 1) (match_dup 2)))]
-  "TARGET_POWERPC64 && TARGET_UPDATE"
+  "TARGET_POWERPC64 && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (Pmode)
+       || !gpc_reg_operand (operands[2], Pmode)
+       || (REG_P (operands[0])
+          && REGNO (operands[0]) == STACK_POINTER_REGNUM))"
+  "@
+   stdux %3,%0,%2
+   stdu %3,%2(%0)"
+  [(set_attr "type" "store_ux,store_u")])
+
+;; This pattern is only conditional on TARGET_POWERPC64, as it is
+;; needed for stack allocation, even if the user passes -mno-update.
+(define_insn "movdi_<mode>_update_stack"
+  [(set (mem:DI (plus:P (match_operand:P 1 "gpc_reg_operand" "0,0")
+                        (match_operand:P 2 "reg_or_aligned_short_operand" "r,I")))
+       (match_operand:DI 3 "gpc_reg_operand" "r,r"))
+   (set (match_operand:P 0 "gpc_reg_operand" "=b,b")
+       (plus:P (match_dup 1) (match_dup 2)))]
+  "TARGET_POWERPC64"
   "@
    stdux %3,%0,%2
    stdu %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_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    {lux|lwzux} %3,%0,%2
    {lu|lwzu} %3,%2(%0)"
                          (match_operand:DI 2 "gpc_reg_operand" "r")))))
    (set (match_operand:DI 0 "gpc_reg_operand" "=b")
        (plus:DI (match_dup 1) (match_dup 2)))]
-  "TARGET_POWERPC64"
+  "TARGET_POWERPC64 && rs6000_gen_cell_microcode
+   && !avoiding_indexed_address_p (DImode)"
   "lwaux %3,%0,%2"
   [(set_attr "type" "load_ext_ux")])
 
        (match_operand:SI 3 "gpc_reg_operand" "r,r"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode)
+       || (REG_P (operands[0])
+          && REGNO (operands[0]) == STACK_POINTER_REGNUM))"
+  "@
+   {stux|stwux} %3,%0,%2
+   {stu|stwu} %3,%2(%0)"
+  [(set_attr "type" "store_ux,store_u")])
+
+;; This is an unconditional pattern; needed for stack allocation, even
+;; if the user passes -mno-update.
+(define_insn "movsi_update_stack"
+  [(set (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
+                        (match_operand:SI 2 "reg_or_short_operand" "r,I")))
+       (match_operand:SI 3 "gpc_reg_operand" "r,r"))
+   (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
+       (plus:SI (match_dup 1) (match_dup 2)))]
+  ""
   "@
    {stux|stwux} %3,%0,%2
    {stu|stwu} %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_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    lhzux %3,%0,%2
    lhzu %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_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    lhzux %3,%0,%2
    lhzu %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_UPDATE"
+  "TARGET_UPDATE && rs6000_gen_cell_microcode
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    lhaux %3,%0,%2
    lhau %3,%2(%0)"
        (match_operand:HI 3 "gpc_reg_operand" "r,r"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    sthux %3,%0,%2
    sthu %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_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    lbzux %3,%0,%2
    lbzu %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_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    lbzux %3,%0,%2
    lbzu %3,%2(%0)"
        (match_operand:QI 3 "gpc_reg_operand" "r,r"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_UPDATE"
+  "TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    stbux %3,%0,%2
    stbu %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 && TARGET_FPRS && TARGET_UPDATE"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    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 && TARGET_FPRS && TARGET_UPDATE"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    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_SOFT_FLOAT || !TARGET_FPRS) && TARGET_UPDATE"
+  "(TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    {lux|lwzux} %3,%0,%2
    {lu|lwzu} %3,%2(%0)"
        (match_operand:SF 3 "gpc_reg_operand" "r,r"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  "(TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_UPDATE"
+  "(TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    {stux|stwux} %3,%0,%2
    {stu|stwu} %3,%2(%0)"
   [(set_attr "type" "store_ux,store_u")])
 
 (define_insn "*movdf_update1"
-  [(set (match_operand:DF 3 "gpc_reg_operand" "=f,f")
+  [(set (match_operand:DF 3 "gpc_reg_operand" "=d,d")
        (mem:DF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,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 && TARGET_FPRS && TARGET_UPDATE"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    lfdux %3,%0,%2
    lfdu %3,%2(%0)"
 (define_insn "*movdf_update2"
   [(set (mem:DF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0")
                         (match_operand:SI 2 "reg_or_short_operand" "r,I")))
-       (match_operand:DF 3 "gpc_reg_operand" "f,f"))
+       (match_operand:DF 3 "gpc_reg_operand" "d,d"))
    (set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
        (plus:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_UPDATE"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_UPDATE
+   && (!avoiding_indexed_address_p (SImode)
+       || !gpc_reg_operand (operands[2], SImode))"
   "@
    stfdux %3,%0,%2
    stfdu %3,%2(%0)"
    (set (match_operand:DF 2 "gpc_reg_operand" "")
        (match_operand:DF 3 "memory_operand" ""))]
   "TARGET_POWER2
-   && TARGET_HARD_FLOAT && TARGET_FPRS
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
    && registers_ok_for_quad_peep (operands[0], operands[2])
    && mems_ok_for_quad_peep (operands[1], operands[3])"
   [(set (match_dup 0)
    (set (match_operand:DF 2 "memory_operand" "")
        (match_operand:DF 3 "gpc_reg_operand" ""))]
   "TARGET_POWER2
-   && TARGET_HARD_FLOAT && TARGET_FPRS
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
    && registers_ok_for_quad_peep (operands[1], operands[3])
    && mems_ok_for_quad_peep (operands[0], operands[2])"
   [(set (match_dup 0)
   "peep2_reg_dead_p (2, operands[0])"
   [(set (match_dup 2) (match_dup 1))])
 
-\f
-;; TLS support.
+\f
+;; TLS support.
+
+;; Mode attributes for different ABIs.
+(define_mode_iterator TLSmode [(SI "! TARGET_64BIT") (DI "TARGET_64BIT")])
+(define_mode_attr tls_abi_suffix [(SI "32") (DI "64")])
+(define_mode_attr tls_sysv_suffix [(SI "si") (DI "di")])
+(define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")])
+
+(define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
+             (match_operand 4 "" "g")))
+   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
+                   (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                  UNSPEC_TLSGD)
+   (clobber (reg:SI LR_REGNO))]
+  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
+{
+  if (TARGET_CMODEL != CMODEL_SMALL)
+    return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;bl %z3\;%.";
+  else
+    return "addi %0,%1,%2@got@tlsgd\;bl %z3\;%.";
+}
+  "&& TARGET_TLS_MARKERS"
+  [(set (match_dup 0)
+       (unspec:TLSmode [(match_dup 1)
+                        (match_dup 2)]
+                       UNSPEC_TLSGD))
+   (parallel [(set (match_dup 0)
+                  (call (mem:TLSmode (match_dup 3))
+                        (match_dup 4)))
+             (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "two")
+   (set (attr "length")
+     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+                  (const_int 16)
+                  (const_int 12)))])
+
+(define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
+             (match_operand 4 "" "g")))
+   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
+                   (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                  UNSPEC_TLSGD)
+   (clobber (reg:SI LR_REGNO))]
+  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
+{
+  if (flag_pic)
+    {
+      if (TARGET_SECURE_PLT && flag_pic == 2)
+       return "addi %0,%1,%2@got@tlsgd\;bl %z3+32768@plt";
+      else
+       return "addi %0,%1,%2@got@tlsgd\;bl %z3@plt";
+    }
+  else
+    return "addi %0,%1,%2@got@tlsgd\;bl %z3";
+}
+  "&& TARGET_TLS_MARKERS"
+  [(set (match_dup 0)
+       (unspec:TLSmode [(match_dup 1)
+                        (match_dup 2)]
+                       UNSPEC_TLSGD))
+   (parallel [(set (match_dup 0)
+                  (call (mem:TLSmode (match_dup 3))
+                        (match_dup 4)))
+             (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "two")
+   (set_attr "length" "8")])
+
+(define_insn_and_split "*tls_gd<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
+                        (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                       UNSPEC_TLSGD))]
+  "HAVE_AS_TLS && TARGET_TLS_MARKERS"
+  "addi %0,%1,%2@got@tlsgd"
+  "&& TARGET_CMODEL != CMODEL_SMALL"
+  [(set (match_dup 3)
+       (const:TLSmode
+         (plus:TLSmode (match_dup 1)
+           (high:TLSmode
+             (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))))
+   (set (match_dup 0)
+       (lo_sum:TLSmode (match_dup 3)
+           (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))]
+  "
+{
+  operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+  [(set (attr "length")
+     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+                  (const_int 8)
+                  (const_int 4)))])
+
+(define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+        (high:TLSmode
+          (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                          UNSPEC_TLSGD)))))]
+  "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+  "addis %0,%1,%2@got@tlsgd@ha"
+  [(set_attr "length" "4")])
 
-;; Mode attributes for different ABIs.
-(define_mode_iterator TLSmode [(SI "! TARGET_64BIT") (DI "TARGET_64BIT")])
-(define_mode_attr tls_abi_suffix [(SI "32") (DI "64")])
-(define_mode_attr tls_sysv_suffix [(SI "si") (DI "di")])
-(define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")])
+(define_insn "*tls_gd_low<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+       (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                      UNSPEC_TLSGD)))]
+  "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+  "addi %0,%1,%2@got@tlsgd@l"
+  [(set_attr "length" "4")])
 
-(define_insn "tls_gd_aix<TLSmode:tls_abi_suffix>"
+(define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
-             (match_operand 4 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-                   (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
                   UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
-  "addi %0,%1,%2@got@tlsgd\;bl %z3\;%."
-  [(set_attr "type" "two")
-   (set_attr "length" "12")])
+  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX && TARGET_TLS_MARKERS"
+  "bl %z1(%3@tlsgd)\;%."
+  [(set_attr "type" "branch")
+   (set_attr "length" "8")])
 
-(define_insn "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
+(define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
-             (match_operand 4 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-                   (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
                   UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
+  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
   if (flag_pic)
     {
       if (TARGET_SECURE_PLT && flag_pic == 2)
-       return "addi %0,%1,%2@got@tlsgd\;bl %z3+32768@plt";
-      else
-       return "addi %0,%1,%2@got@tlsgd\;bl %z3@plt";
+       return "bl %z1+32768(%3@tlsgd)@plt";
+      return "bl %z1(%3@tlsgd)@plt";
     }
-  else
-    return "addi %0,%1,%2@got@tlsgd\;bl %z3";
+  return "bl %z1(%3@tlsgd)";
 }
-  [(set_attr "type" "two")
-   (set_attr "length" "8")])
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
 
-(define_insn "tls_ld_aix<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
         (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s"))
              (match_operand 3 "" "g")))
                   UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
-  "addi %0,%1,%&@got@tlsld\;bl %z2\;%."
-  [(set_attr "length" "12")])
+{
+  if (TARGET_CMODEL != CMODEL_SMALL)
+    return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;bl %z2\;%.";
+  else
+    return "addi %0,%1,%&@got@tlsld\;bl %z2\;%.";
+}
+  "&& TARGET_TLS_MARKERS"
+  [(set (match_dup 0)
+       (unspec:TLSmode [(match_dup 1)]
+                       UNSPEC_TLSLD))
+   (parallel [(set (match_dup 0)
+                  (call (mem:TLSmode (match_dup 2))
+                        (match_dup 3)))
+             (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "two")
+   (set (attr "length")
+     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+                  (const_int 16)
+                  (const_int 12)))])
 
-(define_insn "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
+(define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
         (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s"))
              (match_operand 3 "" "g")))
   else
     return "addi %0,%1,%&@got@tlsld\;bl %z2";
 }
+  "&& TARGET_TLS_MARKERS"
+  [(set (match_dup 0)
+       (unspec:TLSmode [(match_dup 1)]
+                       UNSPEC_TLSLD))
+   (parallel [(set (match_dup 0)
+                  (call (mem:TLSmode (match_dup 2))
+                        (match_dup 3)))
+             (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+             (clobber (reg:SI LR_REGNO))])]
+  ""
   [(set_attr "length" "8")])
 
+(define_insn_and_split "*tls_ld<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
+                       UNSPEC_TLSLD))]
+  "HAVE_AS_TLS && TARGET_TLS_MARKERS"
+  "addi %0,%1,%&@got@tlsld"
+  "&& TARGET_CMODEL != CMODEL_SMALL"
+  [(set (match_dup 2)
+       (const:TLSmode
+         (plus:TLSmode (match_dup 1)
+           (high:TLSmode
+             (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))))
+   (set (match_dup 0)
+       (lo_sum:TLSmode (match_dup 2)
+           (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))]
+  "
+{
+  operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+  [(set (attr "length")
+     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+                  (const_int 8)
+                  (const_int 4)))])
+
+(define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+        (high:TLSmode
+          (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))))]
+  "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+  "addis %0,%1,%&@got@tlsld@ha"
+  [(set_attr "length" "4")])
+
+(define_insn "*tls_ld_low<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+       (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))]
+  "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+  "addi %0,%1,%&@got@tlsld@l"
+  [(set_attr "length" "4")])
+
+(define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+   (clobber (reg:SI LR_REGNO))]
+  "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX && TARGET_TLS_MARKERS"
+  "bl %z1(%&@tlsld)\;%."
+  [(set_attr "type" "branch")
+   (set_attr "length" "8")])
+
+(define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+   (clobber (reg:SI LR_REGNO))]
+  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
+{
+  if (flag_pic)
+    {
+      if (TARGET_SECURE_PLT && flag_pic == 2)
+       return "bl %z1+32768(%&@tlsld)@plt";
+      return "bl %z1(%&@tlsld)@plt";
+    }
+  return "bl %z1(%&@tlsld)";
+}
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
 (define_insn "tls_dtprel_<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
        (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
   "HAVE_AS_TLS"
   "addi %0,%1,%2@dtprel@l")
 
-(define_insn "tls_got_dtprel_<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "tls_got_dtprel_<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
        (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
                         (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
                        UNSPEC_TLSGOTDTPREL))]
   "HAVE_AS_TLS"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)")
+  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)"
+  "&& TARGET_CMODEL != CMODEL_SMALL"
+  [(set (match_dup 3)
+       (const:TLSmode
+         (plus:TLSmode (match_dup 1)
+           (high:TLSmode
+             (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))))
+   (set (match_dup 0)
+       (lo_sum:TLSmode (match_dup 3)
+           (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
+  "
+{
+  operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+  [(set (attr "length")
+     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+                  (const_int 8)
+                  (const_int 4)))])
+
+(define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+        (high:TLSmode
+          (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                          UNSPEC_TLSGOTDTPREL)))))]
+  "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+  "addis %0,%1,%2@got@dtprel@ha"
+  [(set_attr "length" "4")])
+
+(define_insn "*tls_got_dtprel_low<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
+     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+        (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                        UNSPEC_TLSGOTDTPREL)))]
+  "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel@l(%1)"
+  [(set_attr "length" "4")])
 
 (define_insn "tls_tprel_<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
 ;; "b" output constraint here and on tls_tls input to support linker tls
 ;; optimization.  The linker may edit the instructions emitted by a
 ;; tls_got_tprel/tls_tls pair to addis,addi.
-(define_insn "tls_got_tprel_<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "tls_got_tprel_<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
        (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
                         (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
                        UNSPEC_TLSGOTTPREL))]
   "HAVE_AS_TLS"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)")
+  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)"
+  "&& TARGET_CMODEL != CMODEL_SMALL"
+  [(set (match_dup 3)
+       (const:TLSmode
+         (plus:TLSmode (match_dup 1)
+           (high:TLSmode
+             (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))))
+   (set (match_dup 0)
+       (lo_sum:TLSmode (match_dup 3)
+           (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))]
+  "
+{
+  operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+  [(set (attr "length")
+     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+                  (const_int 8)
+                  (const_int 4)))])
+
+(define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+     (const:TLSmode
+       (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+        (high:TLSmode
+          (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                          UNSPEC_TLSGOTTPREL)))))]
+  "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+  "addis %0,%1,%2@got@tprel@ha"
+  [(set_attr "length" "4")])
+
+(define_insn "*tls_got_tprel_low<TLSmode:tls_abi_suffix>"
+  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
+     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+        (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+                        UNSPEC_TLSGOTTPREL)))]
+  "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel@l(%1)"
+  [(set_attr "length" "4")])
 
 (define_insn "tls_tls_<TLSmode:tls_abi_suffix>"
   [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
                        UNSPEC_TLSTLS))]
   "HAVE_AS_TLS"
   "add %0,%1,%2@tls")
-
 \f
 ;; Next come insns related to the calling sequence.
 ;;
 { rtx chain = gen_reg_rtx (Pmode);
   rtx stack_bot = gen_rtx_MEM (Pmode, stack_pointer_rtx);
   rtx neg_op0;
+  rtx insn, par, set, mem;
 
   emit_move_insn (chain, stack_bot);
 
   else
     neg_op0 = GEN_INT (- INTVAL (operands[1]));
 
-  if (TARGET_UPDATE)
-    emit_insn ((* ((TARGET_32BIT) ? gen_movsi_update : gen_movdi_di_update))
-               (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain));
-
-  else
-    {
-      emit_insn ((* ((TARGET_32BIT) ? gen_addsi3 : gen_adddi3))
-                (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
-      emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), chain);
-    }
+  insn = emit_insn ((* ((TARGET_32BIT) ? gen_movsi_update_stack
+                                      : gen_movdi_di_update_stack))
+                       (stack_pointer_rtx, stack_pointer_rtx, neg_op0,
+                        chain));
+  /* Since we didn't use gen_frame_mem to generate the MEM, grab
+     it now and set the alias set/attributes. The above gen_*_update
+     calls will generate a PARALLEL with the MEM set being the first
+     operation. */
+  par = PATTERN (insn);
+  gcc_assert (GET_CODE (par) == PARALLEL);
+  set = XVECEXP (par, 0, 0);
+  gcc_assert (GET_CODE (set) == SET);
+  mem = SET_DEST (set);
+  gcc_assert (MEM_P (mem));
+  MEM_NOTRAP_P (mem) = 1;
+  set_mem_alias_set (mem, get_frame_alias_set ());
 
   emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
   DONE;
 
 (define_insn "load_toc_v4_PIC_1b"
   [(set (reg:SI LR_REGNO)
-       (unspec:SI [(match_operand:SI 0 "immediate_operand" "s")]
-               UNSPEC_TOCPTR))]
+       (unspec:SI [(match_operand:SI 0 "immediate_operand" "s")
+                   (label_ref (match_operand 1 "" ""))]
+               UNSPEC_TOCPTR))
+   (match_dup 1)]
   "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
-  "bcl 20,31,$+8\\n\\t.long %0-$"
+  "bcl 20,31,$+8\;.long %0-$"
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
   [(set_attr "type" "load")])
 
 (define_insn "load_toc_v4_PIC_3b"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
-       (plus:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b")
                 (high:SI
                   (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s")
                             (match_operand:SI 3 "symbol_ref_operand" "s")))))]
                   (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s")
                             (match_operand:SI 3 "symbol_ref_operand" "s"))))]
   "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic"
-  "{cal|addi} %0,%1,%2-%3@l")
+  "{cal %0,%2-%3@l(%1)|addi %0,%1,%2-%3@l}")
 
 ;; If the TOC is shared over a translation unit, as happens with all
 ;; the kinds of PIC that we support, we need to restore the TOC
 #if TARGET_MACHO
   if (DEFAULT_ABI == ABI_DARWIN)
     {
-      const char *picbase = machopic_function_base_name ();
-      rtx picrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (picbase));
+      rtx picrtx = gen_rtx_SYMBOL_REF (Pmode, MACHOPIC_FUNCTION_BASE_NAME);
       rtx picreg = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
       rtx tmplabrtx;
       char tmplab[20];
 
+      crtl->uses_pic_offset_table = 1;
       ASM_GENERATE_INTERNAL_LABEL(tmplab, \"LSJR\",
                                  CODE_LABEL_NUMBER (operands[0]));
       tmplabrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (tmplab));
    "@
     {cal|la} %0,%2@l(%1)
     {ai|addic} %0,%1,%K2")
+
+;; Largetoc support
+(define_insn "largetoc_high"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=b")
+       (const:DI
+         (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b")
+                  (high:DI (match_operand:DI 2 "" "")))))]
+   "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
+   "{cau|addis} %0,%1,%2@ha")
+
+(define_insn "largetoc_low"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+        (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b")
+                  (match_operand:DI 2 "" "")))]
+   "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
+   "{cal %0,%2@l(%1)|addi %0,%1,%2@l}")
 \f
 ;; A function pointer under AIX is a pointer to a data area whose first word
 ;; contains the actual address of the function, whose second word contains a
        (mem:SI (match_operand:SI 0 "gpc_reg_operand" "")))
    (set (mem:SI (plus:SI (reg:SI 1) (const_int 20)))
        (reg:SI 2))
-   (set (reg:SI 2)
-       (mem:SI (plus:SI (match_dup 0)
-                        (const_int 4))))
    (set (reg:SI 11)
        (mem:SI (plus:SI (match_dup 0)
                         (const_int 8))))
    (parallel [(call (mem:SI (match_dup 2))
                    (match_operand 1 "" ""))
-             (use (reg:SI 2))
+             (use (mem:SI (plus:SI (match_dup 0) (const_int 4))))
              (use (reg:SI 11))
-             (set (reg:SI 2)
-                  (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
+             (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
              (clobber (reg:SI LR_REGNO))])]
   "TARGET_32BIT"
   "
        (mem:DI (match_operand:DI 0 "gpc_reg_operand" "")))
    (set (mem:DI (plus:DI (reg:DI 1) (const_int 40)))
        (reg:DI 2))
-   (set (reg:DI 2)
-       (mem:DI (plus:DI (match_dup 0)
-                        (const_int 8))))
    (set (reg:DI 11)
        (mem:DI (plus:DI (match_dup 0)
                         (const_int 16))))
    (parallel [(call (mem:SI (match_dup 2))
                    (match_operand 1 "" ""))
-             (use (reg:DI 2))
+             (use (mem:DI (plus:DI (match_dup 0) (const_int 8))))
              (use (reg:DI 11))
-             (set (reg:DI 2)
-                  (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
+             (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
              (clobber (reg:SI LR_REGNO))])]
   "TARGET_64BIT"
   "
        (mem:SI (match_operand:SI 1 "gpc_reg_operand" "")))
    (set (mem:SI (plus:SI (reg:SI 1) (const_int 20)))
        (reg:SI 2))
-   (set (reg:SI 2)
-       (mem:SI (plus:SI (match_dup 1)
-                        (const_int 4))))
    (set (reg:SI 11)
        (mem:SI (plus:SI (match_dup 1)
                         (const_int 8))))
    (parallel [(set (match_operand 0 "" "")
                   (call (mem:SI (match_dup 3))
                         (match_operand 2 "" "")))
-             (use (reg:SI 2))
+             (use (mem:SI (plus:SI (match_dup 1) (const_int 4))))
              (use (reg:SI 11))
-             (set (reg:SI 2)
-                  (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
+             (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
              (clobber (reg:SI LR_REGNO))])]
   "TARGET_32BIT"
   "
        (mem:DI (match_operand:DI 1 "gpc_reg_operand" "")))
    (set (mem:DI (plus:DI (reg:DI 1) (const_int 40)))
        (reg:DI 2))
-   (set (reg:DI 2)
-       (mem:DI (plus:DI (match_dup 1)
-                        (const_int 8))))
    (set (reg:DI 11)
        (mem:DI (plus:DI (match_dup 1)
                         (const_int 16))))
    (parallel [(set (match_operand 0 "" "")
                   (call (mem:SI (match_dup 3))
                         (match_operand 2 "" "")))
-             (use (reg:DI 2))
+             (use (mem:DI (plus:DI (match_dup 1) (const_int 8))))
              (use (reg:DI 11))
-             (set (reg:DI 2)
-                  (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
+             (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
              (clobber (reg:SI LR_REGNO))])]
   "TARGET_64BIT"
   "
 
   operands[0] = XEXP (operands[0], 0);
 
-  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
-      && flag_pic
-      && GET_CODE (operands[0]) == SYMBOL_REF
-      && !SYMBOL_REF_LOCAL_P (operands[0]))
-    {
-      rtx call;
-      rtvec tmp;
-
-      tmp = gen_rtvec (3,
-                      gen_rtx_CALL (VOIDmode,
-                                    gen_rtx_MEM (SImode, operands[0]),
-                                    operands[1]),
-                      gen_rtx_USE (VOIDmode, operands[2]),
-                      gen_rtx_CLOBBER (VOIDmode,
-                                       gen_rtx_REG (Pmode, LR_REGNO)));
-      call = emit_call_insn (gen_rtx_PARALLEL (VOIDmode, tmp));
-      use_reg (&CALL_INSN_FUNCTION_USAGE (call), pic_offset_table_rtx);
-      DONE;
-    }
-
   if (GET_CODE (operands[0]) != SYMBOL_REF
       || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0]))
       || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
 
   operands[1] = XEXP (operands[1], 0);
 
-  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
-      && flag_pic
-      && GET_CODE (operands[1]) == SYMBOL_REF
-      && !SYMBOL_REF_LOCAL_P (operands[1]))
-    {
-      rtx call;
-      rtvec tmp;
-
-      tmp = gen_rtvec (3,
-                      gen_rtx_SET (VOIDmode,
-                                   operands[0],
-                                   gen_rtx_CALL (VOIDmode,
-                                                 gen_rtx_MEM (SImode,
-                                                              operands[1]),
-                                                 operands[2])),
-                      gen_rtx_USE (VOIDmode, operands[3]),
-                      gen_rtx_CLOBBER (VOIDmode, 
-                                       gen_rtx_REG (Pmode, LR_REGNO)));
-      call = emit_call_insn (gen_rtx_PARALLEL (VOIDmode, tmp));
-      use_reg (&CALL_INSN_FUNCTION_USAGE (call), pic_offset_table_rtx);
-      DONE;
-    }
-
   if (GET_CODE (operands[1]) != SYMBOL_REF
       || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1]))
       || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
 ;; variable argument function.  It is > 0 if FP registers were passed
 ;; and < 0 if they were not.
 
+(define_insn_and_split "*call_indirect_nonlocal_aix32_internal"
+  [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l"))
+                (match_operand 1 "" "g,g"))
+   (use (mem:SI (plus:SI (match_operand:SI 2 "register_operand" "b,b") (const_int 4))))
+   (use (reg:SI 11))
+   (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
+   (clobber (reg:SI LR_REGNO))]
+  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX"
+  "#"
+  "&& reload_completed"
+  [(set (reg:SI 2)
+       (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+   (parallel [(call (mem:SI (match_dup 0))
+                   (match_dup 1))
+             (use (reg:SI 2))
+             (use (reg:SI 11))
+             (set (reg:SI 2)
+                  (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 (define_insn "*call_indirect_nonlocal_aix32"
   [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l"))
         (match_operand 1 "" "g,g"))
    (set (reg:SI 2)
        (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
    (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX"
+  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
   "b%T0l\;{l|lwz} 2,20(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
   "bl %z0\;%."
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
+   
+(define_insn_and_split "*call_indirect_nonlocal_aix64_internal"
+  [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l"))
+                (match_operand 1 "" "g,g"))
+   (use (mem:DI (plus:DI (match_operand:DI 2 "register_operand" "b,b")
+                        (const_int 8))))
+   (use (reg:DI 11))
+   (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
+   (clobber (reg:SI LR_REGNO))]
+  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX"
+  "#"
+  "&& reload_completed"
+  [(set (reg:DI 2)
+       (mem:DI (plus:DI (match_dup 2) (const_int 8))))
+   (parallel [(call (mem:SI (match_dup 0))
+                   (match_dup 1))
+             (use (reg:DI 2))
+             (use (reg:DI 11))
+             (set (reg:DI 2)
+                  (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
 
 (define_insn "*call_indirect_nonlocal_aix64"
   [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l"))
    (set (reg:DI 2)
        (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
    (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX"
+  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
   "b%T0l\;ld 2,40(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
+(define_insn_and_split "*call_value_indirect_nonlocal_aix32_internal"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l"))
+                     (match_operand 2 "" "g,g")))
+       (use (mem:SI (plus:SI (match_operand:SI 3 "register_operand" "b,b")
+                             (const_int 4))))
+       (use (reg:SI 11))
+       (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
+       (clobber (reg:SI LR_REGNO))]
+  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX"
+  "#"
+  "&& reload_completed"
+  [(set (reg:SI 2)
+       (mem:SI (plus:SI (match_dup 3) (const_int 4))))
+   (parallel [(set (match_dup 0) (call (mem:SI (match_dup 1))
+                                      (match_dup 2)))
+             (use (reg:SI 2))
+             (use (reg:SI 11))
+             (set (reg:SI 2)
+                  (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 (define_insn "*call_value_indirect_nonlocal_aix32"
   [(set (match_operand 0 "" "")
        (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l"))
    (set (reg:SI 2)
        (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
    (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX"
+  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
   "b%T1l\;{l|lwz} 2,20(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
+(define_insn_and_split "*call_value_indirect_nonlocal_aix64_internal"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l"))
+                     (match_operand 2 "" "g,g")))
+       (use (mem:DI (plus:DI (match_operand:DI 3 "register_operand" "b,b")
+                             (const_int 8))))
+       (use (reg:DI 11))
+       (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
+       (clobber (reg:SI LR_REGNO))]
+  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX"
+  "#"
+  "&& reload_completed"
+  [(set (reg:DI 2)
+       (mem:DI (plus:DI (match_dup 3) (const_int 8))))
+   (parallel [(set (match_dup 0) (call (mem:SI (match_dup 1))
+                                      (match_dup 2)))
+             (use (reg:DI 2))
+             (use (reg:DI 11))
+             (set (reg:DI 2)
+                  (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
+             (clobber (reg:SI LR_REGNO))])]
+  ""
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
 (define_insn "*call_value_indirect_nonlocal_aix64"
   [(set (match_operand 0 "" "")
        (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l"))
    (set (reg:DI 2)
        (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
    (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX"
+  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
   "b%T1l\;ld 2,40(1)"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
   [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
    (set_attr "length" "4,4,8,8")])
 
-(define_insn "*call_nonlocal_sysv<mode>"
+(define_insn_and_split "*call_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
         (match_operand 1 "" "g,g"))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
 #else
   if (DEFAULT_ABI == ABI_V4 && flag_pic)
     {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-       /* The magic 32768 offset here and in the other sysv call insns
-          corresponds to the offset of r30 in .got2, as given by LCTOC1.
-          See sysv4.h:toc_section.  */
-       return "bl %z0+32768@plt";
-      else
-       return "bl %z0@plt";
+      gcc_assert (!TARGET_SECURE_PLT);
+      return "bl %z0@plt";
     }
   else
     return "bl %z0";
 #endif
 }
+  "DEFAULT_ABI == ABI_V4
+   && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
+   && (INTVAL (operands[2]) & CALL_LONG) == 0"
+  [(parallel [(call (mem:SI (match_dup 0))
+                   (match_dup 1))
+             (use (match_dup 2))
+             (use (match_dup 3))
+             (clobber (reg:SI LR_REGNO))])]
+{
+  operands[3] = pic_offset_table_rtx;
+}
+  [(set_attr "type" "branch,branch")
+   (set_attr "length" "4,8")])
+
+(define_insn "*call_nonlocal_sysv_secure<mode>"
+  [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
+        (match_operand 1 "" "g,g"))
+   (use (match_operand:SI 2 "immediate_operand" "O,n"))
+   (use (match_operand:SI 3 "register_operand" "r,r"))
+   (clobber (reg:SI LR_REGNO))]
+  "(DEFAULT_ABI == ABI_V4
+    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
+    && (INTVAL (operands[2]) & CALL_LONG) == 0)"
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn ("crxor 6,6,6", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn ("creqv 6,6,6", operands);
+
+  if (flag_pic == 2)
+    /* The magic 32768 offset here and in the other sysv call insns
+       corresponds to the offset of r30 in .got2, as given by LCTOC1.
+       See sysv4.h:toc_section.  */
+    return "bl %z0+32768@plt";
+  else
+    return "bl %z0@plt";
+}
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
 
   [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
    (set_attr "length" "4,4,8,8")])
 
-(define_insn "*call_value_nonlocal_sysv<mode>"
+(define_insn_and_split "*call_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
              (match_operand 2 "" "g,g")))
 #else
   if (DEFAULT_ABI == ABI_V4 && flag_pic)
     {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-       return "bl %z1+32768@plt";
-      else
-       return "bl %z1@plt";
+      gcc_assert (!TARGET_SECURE_PLT);
+      return "bl %z1@plt";
     }
   else
-    return "bl %z1";
-#endif
+    return "bl %z1";
+#endif
+}
+  "DEFAULT_ABI == ABI_V4
+   && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
+   && (INTVAL (operands[3]) & CALL_LONG) == 0"
+  [(parallel [(set (match_dup 0)
+                  (call (mem:SI (match_dup 1))
+                        (match_dup 2)))
+             (use (match_dup 3))
+             (use (match_dup 4))
+             (clobber (reg:SI LR_REGNO))])]
+{
+  operands[4] = pic_offset_table_rtx;
+}
+  [(set_attr "type" "branch,branch")
+   (set_attr "length" "4,8")])
+
+(define_insn "*call_value_nonlocal_sysv_secure<mode>"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
+   (use (match_operand:SI 4 "register_operand" "r,r"))
+   (clobber (reg:SI LR_REGNO))]
+  "(DEFAULT_ABI == ABI_V4
+    && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
+    && (INTVAL (operands[3]) & CALL_LONG) == 0)"
+{
+  if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn ("crxor 6,6,6", operands);
+
+  else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn ("creqv 6,6,6", operands);
+
+  if (flag_pic == 2)
+    return "bl %z1+32768@plt";
+  else
+    return "bl %z1@plt";
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
-(define_insn "*sibcall_nonlocal_aix32"
-  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s"))
-        (match_operand 1 "" "g"))
-   (use (match_operand:SI 2 "immediate_operand" "O"))
-   (use (reg:SI LR_REGNO))
-   (return)]
-  "TARGET_32BIT
-   && DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[2]) & CALL_LONG) == 0"
-  "b %z0"
-  [(set_attr "type" "branch")
-   (set_attr "length" "4")])
-
-(define_insn "*sibcall_nonlocal_aix64"
-  [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s"))
-        (match_operand 1 "" "g"))
-   (use (match_operand:SI 2 "immediate_operand" "O"))
+(define_insn "*sibcall_nonlocal_aix<mode>"
+  [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
+        (match_operand 1 "" "g,g"))
+   (use (match_operand:SI 2 "immediate_operand" "O,O"))
    (use (reg:SI LR_REGNO))
    (return)]
-  "TARGET_64BIT
-   && DEFAULT_ABI == ABI_AIX
+  "DEFAULT_ABI == ABI_AIX
    && (INTVAL (operands[2]) & CALL_LONG) == 0"
-  "b %z0"
-  [(set_attr "type" "branch")
-   (set_attr "length" "4")])
-
-(define_insn "*sibcall_value_nonlocal_aix32"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s"))
-             (match_operand 2 "" "g")))
-   (use (match_operand:SI 3 "immediate_operand" "O"))
-   (use (reg:SI LR_REGNO))
-   (return)]
-  "TARGET_32BIT
-   && DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[3]) & CALL_LONG) == 0"
-  "b %z1"
+  "@
+   b %z0
+   b%T0"
   [(set_attr "type" "branch")
    (set_attr "length" "4")])
 
-(define_insn "*sibcall_value_nonlocal_aix64"
+(define_insn "*sibcall_value_nonlocal_aix<mode>"
   [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s"))
-             (match_operand 2 "" "g")))
-   (use (match_operand:SI 3 "immediate_operand" "O"))
+       (call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:SI 3 "immediate_operand" "O,O"))
    (use (reg:SI LR_REGNO))
    (return)]
-  "TARGET_64BIT
-   && DEFAULT_ABI == ABI_AIX
+  "DEFAULT_ABI == ABI_AIX
    && (INTVAL (operands[3]) & CALL_LONG) == 0"
-  "b %z1"
+  "@
+   b %z1
+   b%T1"
   [(set_attr "type" "branch")
    (set_attr "length" "4")])
 
 (define_insn "*sibcall_nonlocal_sysv<mode>"
-  [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
+  [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c"))
         (match_operand 1 "" ""))
-   (use (match_operand 2 "immediate_operand" "O,n"))
+   (use (match_operand 2 "immediate_operand" "O,n,O,n"))
    (use (reg:SI LR_REGNO))
    (return)]
   "(DEFAULT_ABI == ABI_DARWIN
-     || DEFAULT_ABI == ABI_V4)
+    || DEFAULT_ABI == ABI_V4)
    && (INTVAL (operands[2]) & CALL_LONG) == 0"
   "*
 {
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn (\"creqv 6,6,6\", operands);
 
-  if (DEFAULT_ABI == ABI_V4 && flag_pic)
+  if (which_alternative >= 2)
+    return \"b%T0\";
+  else if (DEFAULT_ABI == ABI_V4 && flag_pic)
     {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-       return \"b %z0+32768@plt\";
-      else
-       return \"b %z0@plt\";
+      gcc_assert (!TARGET_SECURE_PLT);
+      return \"b %z0@plt\";
     }
   else
     return \"b %z0\";
 }"
-  [(set_attr "type" "branch,branch")
-   (set_attr "length" "4,8")])
+  [(set_attr "type" "branch")
+   (set_attr "length" "4,8,4,8")])
 
 (define_expand "sibcall_value"
   [(parallel [(set (match_operand 0 "register_operand" "")
 
 (define_insn "*sibcall_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
+       (call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c"))
              (match_operand 2 "" "")))
-   (use (match_operand:SI 3 "immediate_operand" "O,n"))
+   (use (match_operand:SI 3 "immediate_operand" "O,n,O,n"))
    (use (reg:SI LR_REGNO))
    (return)]
   "(DEFAULT_ABI == ABI_DARWIN
-       || DEFAULT_ABI == ABI_V4)
+    || DEFAULT_ABI == ABI_V4)
    && (INTVAL (operands[3]) & CALL_LONG) == 0"
   "*
 {
-  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+  if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
     output_asm_insn (\"crxor 6,6,6\", operands);
 
-  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+  else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn (\"creqv 6,6,6\", operands);
 
-  if (DEFAULT_ABI == ABI_V4 && flag_pic)
+  if (which_alternative >= 2)
+    return \"b%T1\";
+  else if (DEFAULT_ABI == ABI_V4 && flag_pic)
     {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-       return \"b %z1+32768@plt\";
-      else
-       return \"b %z1@plt\";
+      gcc_assert (!TARGET_SECURE_PLT);
+      return \"b %z1@plt\";
     }
   else
     return \"b %z1\";
 }"
-  [(set_attr "type" "branch,branch")
-   (set_attr "length" "4,8")])
+  [(set_attr "type" "branch")
+   (set_attr "length" "4,8,4,8")])
 
 (define_expand "sibcall_epilogue"
   [(use (const_int 0))]
   [(unspec_volatile [(const_int 0)] UNSPECV_BLOCK)]
   ""
   "")
+
+(define_insn "probe_stack"
+  [(set (match_operand 0 "memory_operand" "=m")
+        (unspec [(const_int 0)] UNSPEC_PROBE_STACK))]
+  ""
+  "{st%U0%X0|stw%U0%X0} 0,%0"
+  [(set_attr "type" "store")
+   (set_attr "length" "4")])
+
+(define_insn "probe_stack_range<P:mode>"
+  [(set (match_operand:P 0 "register_operand" "=r")
+       (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
+                           (match_operand:P 2 "register_operand" "r")]
+                          UNSPECV_PROBE_STACK_RANGE))]
+  ""
+  "* return output_probe_stack_range (operands[0], operands[2]);"
+  [(set_attr "type" "three")])
 \f
 ;; Compare insns are next.  Note that the RS/6000 has two types of compares,
 ;; signed & unsigned, and one type of branch.
 ;;
 ;; Start with the DEFINE_EXPANDs to generate the rtl for compares, scc
-;; insns, and branches.  We store the operands of compares until we see
-;; how it is used.
-(define_expand "cmp<mode>"
-  [(set (cc0)
-        (compare (match_operand:GPR 0 "gpc_reg_operand" "")
-                (match_operand:GPR 1 "reg_or_short_operand" "")))]
+;; insns, and branches.
+
+(define_expand "cbranch<mode>4"
+  [(use (match_operator 0 "rs6000_cbranch_operator"
+         [(match_operand:GPR 1 "gpc_reg_operand" "")
+          (match_operand:GPR 2 "reg_or_short_operand" "")]))
+   (use (match_operand 3 ""))]
   ""
   "
 {
-  /* Take care of the possibility that operands[1] might be negative but
+  /* Take care of the possibility that operands[2] might be negative but
      this might be a logical operation.  That insn doesn't exist.  */
-  if (GET_CODE (operands[1]) == CONST_INT
-      && INTVAL (operands[1]) < 0)
-    operands[1] = force_reg (<MODE>mode, operands[1]);
-
-  rs6000_compare_op0 = operands[0];
-  rs6000_compare_op1 = operands[1];
-  rs6000_compare_fp_p = 0;
-  DONE;
-}")
+  if (GET_CODE (operands[2]) == CONST_INT
+      && INTVAL (operands[2]) < 0)
+    {
+      operands[2] = force_reg (<MODE>mode, operands[2]);
+      operands[0] = gen_rtx_fmt_ee (GET_CODE (operands[0]),
+                                   GET_MODE (operands[0]),
+                                   operands[1], operands[2]);
+   }
 
-(define_expand "cmp<mode>"
-  [(set (cc0) (compare (match_operand:FP 0 "gpc_reg_operand" "")
-                      (match_operand:FP 1 "gpc_reg_operand" "")))]
-  ""
-  "
-{
-  rs6000_compare_op0 = operands[0];
-  rs6000_compare_op1 = operands[1];
-  rs6000_compare_fp_p = 1;
+  rs6000_emit_cbranch (<MODE>mode, operands);
   DONE;
 }")
 
-(define_expand "beq"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (EQ, operands[0]); DONE; }")
-
-(define_expand "bne"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (NE, operands[0]); DONE; }")
-
-(define_expand "bge"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (GE, operands[0]); DONE; }")
-
-(define_expand "bgt"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (GT, operands[0]); DONE; }")
-
-(define_expand "ble"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (LE, operands[0]); DONE; }")
-
-(define_expand "blt"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (LT, operands[0]); DONE; }")
-
-(define_expand "bgeu"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (GEU, operands[0]); DONE; }")
-
-(define_expand "bgtu"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (GTU, operands[0]); DONE; }")
-
-(define_expand "bleu"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (LEU, operands[0]); DONE; }")
-
-(define_expand "bltu"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (LTU, operands[0]); DONE; }")
-
-(define_expand "bunordered"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (UNORDERED, operands[0]); DONE; }")
-
-(define_expand "bordered"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (ORDERED, operands[0]); DONE; }")
-
-(define_expand "buneq"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (UNEQ, operands[0]); DONE; }")
-
-(define_expand "bunge"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (UNGE, operands[0]); DONE; }")
-
-(define_expand "bungt"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (UNGT, operands[0]); DONE; }")
-
-(define_expand "bunle"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (UNLE, operands[0]); DONE; }")
-
-(define_expand "bunlt"
-  [(use (match_operand 0 "" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_cbranch (UNLT, operands[0]); DONE; }")
-
-(define_expand "bltgt"
-  [(use (match_operand 0 "" ""))]
-  ""
-  "{ rs6000_emit_cbranch (LTGT, operands[0]); DONE; }")
-
-;; For SNE, we would prefer that the xor/abs sequence be used for integers.
-;; For SEQ, likewise, except that comparisons with zero should be done
-;; with an scc insns.  However, due to the order that combine see the
-;; resulting insns, we must, in fact, allow SEQ for integers.  Fail in
-;; the cases we don't want to handle.
-(define_expand "seq"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "{ rs6000_emit_sCOND (EQ, operands[0]); DONE; }")
-
-(define_expand "sne"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+(define_expand "cbranch<mode>4"
+  [(use (match_operator 0 "rs6000_cbranch_operator"
+         [(match_operand:FP 1 "gpc_reg_operand" "")
+          (match_operand:FP 2 "gpc_reg_operand" "")]))
+   (use (match_operand 3 ""))]
   ""
   "
 {
-  if (! rs6000_compare_fp_p)
-    FAIL;
-
-  rs6000_emit_sCOND (NE, operands[0]);
+  rs6000_emit_cbranch (<MODE>mode, operands);
   DONE;
 }")
 
-;; A >= 0 is best done the portable way for A an integer.
-(define_expand "sge"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+(define_expand "cstore<mode>4"
+  [(use (match_operator 1 "rs6000_cbranch_operator"
+         [(match_operand:GPR 2 "gpc_reg_operand" "")
+          (match_operand:GPR 3 "reg_or_short_operand" "")]))
+   (clobber (match_operand:SI 0 "register_operand"))]
   ""
   "
 {
-  if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
-    FAIL;
-
-  rs6000_emit_sCOND (GE, operands[0]);
-  DONE;
-}")
+  /* Take care of the possibility that operands[3] might be negative but
+     this might be a logical operation.  That insn doesn't exist.  */
+  if (GET_CODE (operands[3]) == CONST_INT
+      && INTVAL (operands[3]) < 0)
+    {
+      operands[3] = force_reg (<MODE>mode, operands[3]);
+      operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+                                   GET_MODE (operands[1]),
+                                   operands[2], operands[3]);
+    }
 
-;; A > 0 is best done using the portable sequence, so fail in that case.
-(define_expand "sgt"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "
-{
-  if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
+  /* For SNE, we would prefer that the xor/abs sequence be used for integers.
+     For SEQ, likewise, except that comparisons with zero should be done
+     with an scc insns.  However, due to the order that combine see the
+     resulting insns, we must, in fact, allow SEQ for integers.  Fail in
+     the cases we don't want to handle or are best handled by portable
+     code.  */
+  if (GET_CODE (operands[1]) == NE)
     FAIL;
-
-  rs6000_emit_sCOND (GT, operands[0]);
-  DONE;
-}")
-
-;; A <= 0 is best done the portable way for A an integer.
-(define_expand "sle"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "
-{
-  if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
+  if ((GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LE
+       || GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE)
+      && operands[3] == const0_rtx)
     FAIL;
-
-  rs6000_emit_sCOND (LE, operands[0]);
+  rs6000_emit_sCOND (<MODE>mode, operands);
   DONE;
 }")
 
-;; A < 0 is best done in the portable way for A an integer.
-(define_expand "slt"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+(define_expand "cstore<mode>4"
+  [(use (match_operator 1 "rs6000_cbranch_operator"
+         [(match_operand:FP 2 "gpc_reg_operand" "")
+          (match_operand:FP 3 "gpc_reg_operand" "")]))
+   (clobber (match_operand:SI 0 "register_operand"))]
   ""
   "
 {
-  if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
-    FAIL;
-
-  rs6000_emit_sCOND (LT, operands[0]);
+  rs6000_emit_sCOND (<MODE>mode, operands);
   DONE;
 }")
 
-(define_expand "sgeu"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "{ rs6000_emit_sCOND (GEU, operands[0]); DONE; }")
-
-(define_expand "sgtu"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "{ rs6000_emit_sCOND (GTU, operands[0]); DONE; }")
-
-(define_expand "sleu"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "{ rs6000_emit_sCOND (LEU, operands[0]); DONE; }")
-
-(define_expand "sltu"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "{ rs6000_emit_sCOND (LTU, operands[0]); DONE; }")
-
-(define_expand "sunordered"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (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_FPRS)"
-  "{ rs6000_emit_sCOND (ORDERED, operands[0]); DONE; }")
-
-(define_expand "suneq"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_sCOND (UNEQ, operands[0]); DONE; }")
-
-(define_expand "sunge"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_sCOND (UNGE, operands[0]); DONE; }")
-
-(define_expand "sungt"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_sCOND (UNGT, operands[0]); DONE; }")
-
-(define_expand "sunle"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_sCOND (UNLE, operands[0]); DONE; }")
-
-(define_expand "sunlt"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  "! (TARGET_HARD_FLOAT && !TARGET_FPRS)"
-  "{ rs6000_emit_sCOND (UNLT, operands[0]); DONE; }")
-
-(define_expand "sltgt"
-  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
-  ""
-  "{ rs6000_emit_sCOND (LTGT, operands[0]); DONE; }")
 
 (define_expand "stack_protect_set"
   [(match_operand 0 "memory_operand" "")
    (match_operand 2 "" "")]
   ""
 {
+  rtx test, op0, op1;
 #ifdef TARGET_THREAD_SSP_OFFSET
   rtx tlsreg = gen_rtx_REG (Pmode, TARGET_64BIT ? 13 : 2);
   rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET));
   operands[1] = gen_rtx_MEM (Pmode, addr);
 #endif
-  rs6000_compare_op0 = operands[0];
-  rs6000_compare_op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, operands[1]),
-                                      UNSPEC_SP_TEST);
-  rs6000_compare_fp_p = 0;
-  emit_jump_insn (gen_beq (operands[2]));
+  op0 = operands[0];
+  op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, operands[1]), UNSPEC_SP_TEST);
+  test = gen_rtx_EQ (VOIDmode, op0, op1);
+  emit_jump_insn (gen_cbranchsi4 (test, op0, op1, operands[2]));
   DONE;
 })
 
   [(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 && TARGET_FPRS"
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
   "fcmpu %0,%1,%2"
   [(set_attr "type" "fpcompare")])
 
 (define_insn "*cmpdf_internal1"
   [(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 && TARGET_FPRS"
+       (compare:CCFP (match_operand:DF 1 "gpc_reg_operand" "d")
+                     (match_operand:DF 2 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !VECTOR_UNIT_VSX_P (DFmode)"
   "fcmpu %0,%1,%2"
   [(set_attr "type" "fpcompare")])
 
 ;; Only need to compare second words if first words equal
 (define_insn "*cmptf_internal1"
   [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
-       (compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "f")
-                     (match_operand:TF 2 "gpc_reg_operand" "f")))]
+       (compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "d")
+                     (match_operand:TF 2 "gpc_reg_operand" "d")))]
   "!TARGET_IEEEQUAD && !TARGET_XL_COMPAT
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LONG_DOUBLE_128"
   "fcmpu %0,%1,%2\;bne %0,$+8\;fcmpu %0,%L1,%L2"
   [(set_attr "type" "fpcompare")
    (set_attr "length" "12")])
 
 (define_insn_and_split "*cmptf_internal2"
   [(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
-       (compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "f")
-                     (match_operand:TF 2 "gpc_reg_operand" "f")))
-    (clobber (match_scratch:DF 3 "=f"))
-    (clobber (match_scratch:DF 4 "=f"))
-    (clobber (match_scratch:DF 5 "=f"))
-    (clobber (match_scratch:DF 6 "=f"))
-    (clobber (match_scratch:DF 7 "=f"))
-    (clobber (match_scratch:DF 8 "=f"))
-    (clobber (match_scratch:DF 9 "=f"))
-    (clobber (match_scratch:DF 10 "=f"))]
+       (compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "d")
+                     (match_operand:TF 2 "gpc_reg_operand" "d")))
+    (clobber (match_scratch:DF 3 "=d"))
+    (clobber (match_scratch:DF 4 "=d"))
+    (clobber (match_scratch:DF 5 "=d"))
+    (clobber (match_scratch:DF 6 "=d"))
+    (clobber (match_scratch:DF 7 "=d"))
+    (clobber (match_scratch:DF 8 "=d"))
+    (clobber (match_scratch:DF 9 "=d"))
+    (clobber (match_scratch:DF 10 "=d"))
+    (clobber (match_scratch:GPR 11 "=b"))]
   "!TARGET_IEEEQUAD && TARGET_XL_COMPAT
-   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+   && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LONG_DOUBLE_128"
   "#"
   "&& reload_completed"
-  [(set (match_dup 3) (match_dup 13))
-   (set (match_dup 4) (match_dup 14))
+  [(set (match_dup 3) (match_dup 14))
+   (set (match_dup 4) (match_dup 15))
    (set (match_dup 9) (abs:DF (match_dup 5)))
    (set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 3)))
    (set (pc) (if_then_else (ne (match_dup 0) (const_int 0))
-                          (label_ref (match_dup 11))
+                          (label_ref (match_dup 12))
                           (pc)))
    (set (match_dup 0) (compare:CCFP (match_dup 5) (match_dup 7)))
-   (set (pc) (label_ref (match_dup 12)))
-   (match_dup 11)
+   (set (pc) (label_ref (match_dup 13)))
+   (match_dup 12)
    (set (match_dup 10) (minus:DF (match_dup 5) (match_dup 7)))
    (set (match_dup 9) (minus:DF (match_dup 6) (match_dup 8)))
    (set (match_dup 9) (plus:DF (match_dup 10) (match_dup 9)))
-   (set (match_dup 0) (compare:CCFP (match_dup 7) (match_dup 4)))
-   (match_dup 12)]
+   (set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 4)))
+   (match_dup 13)]
 {
   REAL_VALUE_TYPE rv;
   const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
   operands[6] = simplify_gen_subreg (DFmode, operands[1], TFmode, lo_word);
   operands[7] = simplify_gen_subreg (DFmode, operands[2], TFmode, hi_word);
   operands[8] = simplify_gen_subreg (DFmode, operands[2], TFmode, lo_word);
-  operands[11] = gen_label_rtx ();
   operands[12] = gen_label_rtx ();
+  operands[13] = gen_label_rtx ();
   real_inf (&rv);
-  operands[13] = force_const_mem (DFmode,
-                                 CONST_DOUBLE_FROM_REAL_VALUE (rv, DFmode));
   operands[14] = force_const_mem (DFmode,
+                                 CONST_DOUBLE_FROM_REAL_VALUE (rv, DFmode));
+  operands[15] = force_const_mem (DFmode,
                                  CONST_DOUBLE_FROM_REAL_VALUE (dconst0,
                                                                DFmode));
   if (TARGET_TOC)
     {
-      operands[13] = gen_const_mem (DFmode,
-                                   create_TOC_reference (XEXP (operands[13], 0)));
-      operands[14] = gen_const_mem (DFmode,
-                                   create_TOC_reference (XEXP (operands[14], 0)));
-      set_mem_alias_set (operands[13], get_TOC_alias_set ());
+      rtx tocref;
+      tocref = create_TOC_reference (XEXP (operands[14], 0), operands[11]);
+      operands[14] = gen_const_mem (DFmode, tocref);
+      tocref = create_TOC_reference (XEXP (operands[15], 0), operands[11]);
+      operands[15] = gen_const_mem (DFmode, tocref);
       set_mem_alias_set (operands[14], get_TOC_alias_set ());
+      set_mem_alias_set (operands[15], get_TOC_alias_set ());
     }
 })
 \f
 (define_insn "move_from_CR_gt_bit"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (unspec:SI [(match_operand 1 "cc_reg_operand" "y")] UNSPEC_MV_CR_GT))]
-  "TARGET_E500"
+  "TARGET_HARD_FLOAT && !TARGET_FPRS"
   "mfcr %0\;{rlinm|rlwinm} %0,%0,%D1,31,31"
   [(set_attr "type" "mfcr")
    (set_attr "length" "8")])
    (set_attr "length" "8,16")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (ashift:SI (match_operator:SI 1 "scc_comparison_operator"
                                       [(match_operand 2 "cc_reg_operand" "")
    (set_attr "length" "8,12")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (plus:DI (lshiftrt:DI
                   (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "")))
    (set_attr "length" "8,12")])
 
 (define_split
-  [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (plus:DI (lshiftrt:DI
                   (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "")))
    (set_attr "length" "12,12,16,16")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (geu:P (match_operand:P 1 "gpc_reg_operand" "")
                (match_operand:P 2 "reg_or_neg_short_operand" ""))
    (set_attr "length" "12,16")])
 
 (define_split
-  [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (plus:DI (gt:DI (match_operand:DI 1 "gpc_reg_operand" "")
                         (const_int 0))
    (set_attr "length" "12,16")])
 
 (define_split
-  [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "")
+  [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "")
        (compare:CC
         (plus:DI (gt:DI (match_operand:DI 1 "gpc_reg_operand" "")
                         (const_int 0))
   "{t 31,0,0|trap}"
   [(set_attr "type" "trap")])
 
-(define_expand "conditional_trap"
-  [(trap_if (match_operator 0 "trap_comparison_operator"
-                           [(match_dup 2) (match_dup 3)])
-           (match_operand 1 "const_int_operand" ""))]
+(define_expand "ctrap<mode>4"
+  [(trap_if (match_operator 0 "ordered_comparison_operator"
+                           [(match_operand:GPR 1 "register_operand")
+                            (match_operand:GPR 2 "reg_or_short_operand")])
+           (match_operand 3 "zero_constant" ""))]
   ""
-  "if (rs6000_compare_fp_p || operands[1] != const0_rtx) FAIL;
-   operands[2] = rs6000_compare_op0;
-   operands[3] = rs6000_compare_op1;")
+  "")
 
 (define_insn ""
-  [(trap_if (match_operator 0 "trap_comparison_operator"
+  [(trap_if (match_operator 0 "ordered_comparison_operator"
                             [(match_operand:GPR 1 "register_operand" "r")
                              (match_operand:GPR 2 "reg_or_short_operand" "rI")])
            (const_int 0))]
   "{stm|stmw} %2,%1"
   [(set_attr "type" "store_ux")])
 
-(define_insn "*save_gpregs_<mode>"
+; The following comment applies to:
+;     save_gpregs_*
+;     save_fpregs_*
+;     restore_gpregs*
+;     return_and_restore_gpregs*
+;     return_and_restore_fpregs*
+;     return_and_restore_fpregs_aix*
+;
+; The out-of-line save / restore functions expects one input argument.
+; Since those are not standard call_insn's, we must avoid using
+; MATCH_OPERAND for that argument. That way the register rename
+; optimization will not try to rename this register.
+; Each pattern is repeated for each possible register number used in 
+; various ABIs (r11, r1, and for some functions r12)
+
+(define_insn "*save_gpregs_<mode>_r11"
+  [(match_parallel 0 "any_parallel_operand"
+                  [(clobber (reg:P 65))
+                   (use (match_operand:P 1 "symbol_ref_operand" "s"))
+                    (use (reg:P 11))
+                   (set (match_operand:P 2 "memory_operand" "=m")
+                        (match_operand:P 3 "gpc_reg_operand" "r"))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*save_gpregs_<mode>_r12"
+  [(match_parallel 0 "any_parallel_operand"
+                  [(clobber (reg:P 65))
+                   (use (match_operand:P 1 "symbol_ref_operand" "s"))
+                    (use (reg:P 12))
+                   (set (match_operand:P 2 "memory_operand" "=m")
+                        (match_operand:P 3 "gpc_reg_operand" "r"))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*save_gpregs_<mode>_r1"
+  [(match_parallel 0 "any_parallel_operand"
+                  [(clobber (reg:P 65))
+                   (use (match_operand:P 1 "symbol_ref_operand" "s"))
+                    (use (reg:P 1))
+                   (set (match_operand:P 2 "memory_operand" "=m")
+                        (match_operand:P 3 "gpc_reg_operand" "r"))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*save_fpregs_<mode>_r11"
+  [(match_parallel 0 "any_parallel_operand"
+                  [(clobber (reg:P 65))
+                   (use (match_operand:P 1 "symbol_ref_operand" "s"))
+                    (use (reg:P 11))
+                   (set (match_operand:DF 2 "memory_operand" "=m")
+                        (match_operand:DF 3 "gpc_reg_operand" "d"))])]
+  ""
+  "bl %1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*save_fpregs_<mode>_r12"
   [(match_parallel 0 "any_parallel_operand"
                   [(clobber (reg:P 65))
                    (use (match_operand:P 1 "symbol_ref_operand" "s"))
-                    (use (match_operand:P 2 "gpc_reg_operand" "r"))
-                   (set (match_operand:P 3 "memory_operand" "=m")
-                        (match_operand:P 4 "gpc_reg_operand" "r"))])]
+                    (use (reg:P 12))
+                   (set (match_operand:DF 2 "memory_operand" "=m")
+                        (match_operand:DF 3 "gpc_reg_operand" "d"))])]
   ""
-  "bl %z1"
+  "bl %1"
   [(set_attr "type" "branch")
    (set_attr "length" "4")])
 
-(define_insn "*save_fpregs_<mode>"
+(define_insn "*save_fpregs_<mode>_r1"
   [(match_parallel 0 "any_parallel_operand"
                   [(clobber (reg:P 65))
                    (use (match_operand:P 1 "symbol_ref_operand" "s"))
-                    (use (match_operand:P 2 "gpc_reg_operand" "r"))
-                   (set (match_operand:DF 3 "memory_operand" "=m")
-                        (match_operand:DF 4 "gpc_reg_operand" "f"))])]
+                    (use (reg:P 1))
+                   (set (match_operand:DF 2 "memory_operand" "=m")
+                        (match_operand:DF 3 "gpc_reg_operand" "d"))])]
   ""
-  "bl %z1"
+  "bl %1"
   [(set_attr "type" "branch")
    (set_attr "length" "4")])
 
   ""
   [(set_attr "length" "0")])
 
+; Like stack_tie, but depend on both fp and sp based memory.
+(define_insn "frame_tie"
+  [(set (match_operand:BLK 0 "memory_operand" "+m")
+       (unspec:BLK [(match_dup 0)
+                    (match_operand:BLK 1 "memory_operand" "m")] UNSPEC_TIE))]
+  ""
+  ""
+  [(set_attr "length" "0")])
+
 
 (define_expand "epilogue"
   [(use (const_int 0))]
                                 (match_operand:SI 2 "memory_operand" "m"))])]
   "TARGET_MULTIPLE"
   "{lm|lmw} %1,%2"
-  [(set_attr "type" "load_ux")])
+  [(set_attr "type" "load_ux")
+   (set_attr "cell_micro" "always")])
 
 (define_insn "*return_internal_<mode>"
   [(return)
 ; FIXME: This would probably be somewhat simpler if the Cygnus sibcall
 ; stuff was in GCC.  Oh, and "any_parallel_operand" is a bit flexible...
 
-(define_insn "*restore_gpregs_<mode>"
+; The following comment applies to:
+;     save_gpregs_*
+;     save_fpregs_*
+;     restore_gpregs*
+;     return_and_restore_gpregs*
+;     return_and_restore_fpregs*
+;     return_and_restore_fpregs_aix*
+;
+; The out-of-line save / restore functions expects one input argument.
+; Since those are not standard call_insn's, we must avoid using
+; MATCH_OPERAND for that argument. That way the register rename
+; optimization will not try to rename this register.
+; Each pattern is repeated for each possible register number used in 
+; various ABIs (r11, r1, and for some functions r12)
+
+(define_insn "*restore_gpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+                  [(clobber (match_operand:P 1 "register_operand" "=l"))
+                   (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                   (use (reg:P 11))
+                  (set (match_operand:P 3 "gpc_reg_operand" "=r")
+                       (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "bl %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*restore_gpregs_<mode>_r12"
+ [(match_parallel 0 "any_parallel_operand"
+                  [(clobber (match_operand:P 1 "register_operand" "=l"))
+                   (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                   (use (reg:P 12))
+                  (set (match_operand:P 3 "gpc_reg_operand" "=r")
+                       (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "bl %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*restore_gpregs_<mode>_r1"
  [(match_parallel 0 "any_parallel_operand"
                   [(clobber (match_operand:P 1 "register_operand" "=l"))
                    (use (match_operand:P 2 "symbol_ref_operand" "s"))
-                   (use (match_operand:P 3 "gpc_reg_operand" "r"))
-                  (set (match_operand:P 4 "gpc_reg_operand" "=r")
-                       (match_operand:P 5 "memory_operand" "m"))])]
+                   (use (reg:P 1))
+                  (set (match_operand:P 3 "gpc_reg_operand" "=r")
+                       (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "bl %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_gpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+                  [(return)
+                  (clobber (match_operand:P 1 "register_operand" "=l"))
+                  (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                   (use (reg:P 11))
+                  (set (match_operand:P 3 "gpc_reg_operand" "=r")
+                       (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_gpregs_<mode>_r12"
+ [(match_parallel 0 "any_parallel_operand"
+                  [(return)
+                  (clobber (match_operand:P 1 "register_operand" "=l"))
+                  (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                   (use (reg:P 12))
+                  (set (match_operand:P 3 "gpc_reg_operand" "=r")
+                       (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_gpregs_<mode>_r1"
+ [(match_parallel 0 "any_parallel_operand"
+                  [(return)
+                  (clobber (match_operand:P 1 "register_operand" "=l"))
+                  (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                   (use (reg:P 1))
+                  (set (match_operand:P 3 "gpc_reg_operand" "=r")
+                       (match_operand:P 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_fpregs_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+                  [(return)
+                  (clobber (match_operand:P 1 "register_operand" "=l"))
+                  (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                   (use (reg:P 11))
+                  (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+                       (match_operand:DF 4 "memory_operand" "m"))])]
  ""
- "bl %z2"
+ "b %2"
  [(set_attr "type" "branch")
   (set_attr "length" "4")])
 
-(define_insn "*return_and_restore_gpregs_<mode>"
+(define_insn "*return_and_restore_fpregs_<mode>_r12"
  [(match_parallel 0 "any_parallel_operand"
                   [(return)
                   (clobber (match_operand:P 1 "register_operand" "=l"))
                   (use (match_operand:P 2 "symbol_ref_operand" "s"))
-                   (use (match_operand:P 3 "gpc_reg_operand" "r"))
-                  (set (match_operand:P 4 "gpc_reg_operand" "=r")
-                       (match_operand:P 5 "memory_operand" "m"))])]
+                   (use (reg:P 12))
+                  (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+                       (match_operand:DF 4 "memory_operand" "m"))])]
  ""
- "b %z2"
+ "b %2"
  [(set_attr "type" "branch")
   (set_attr "length" "4")])
 
-(define_insn "*return_and_restore_fpregs_<mode>"
+(define_insn "*return_and_restore_fpregs_<mode>_r1"
  [(match_parallel 0 "any_parallel_operand"
                   [(return)
                   (clobber (match_operand:P 1 "register_operand" "=l"))
                   (use (match_operand:P 2 "symbol_ref_operand" "s"))
-                   (use (match_operand:P 3 "gpc_reg_operand" "r"))
-                  (set (match_operand:DF 4 "gpc_reg_operand" "=f")
-                       (match_operand:DF 5 "memory_operand" "m"))])]
+                   (use (reg:P 1))
+                  (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+                       (match_operand:DF 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_fpregs_aix_<mode>_r11"
+ [(match_parallel 0 "any_parallel_operand"
+                 [(return)
+                  (use (match_operand:P 1 "register_operand" "l"))
+                  (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                  (use (reg:P 11))
+                  (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+                       (match_operand:DF 4 "memory_operand" "m"))])]
+ ""
+ "b %2"
+ [(set_attr "type" "branch")
+  (set_attr "length" "4")])
+
+(define_insn "*return_and_restore_fpregs_aix_<mode>_r1"
+ [(match_parallel 0 "any_parallel_operand"
+                 [(return)
+                  (use (match_operand:P 1 "register_operand" "l"))
+                  (use (match_operand:P 2 "symbol_ref_operand" "s"))
+                  (use (reg:P 1))
+                  (set (match_operand:DF 3 "gpc_reg_operand" "=d")
+                       (match_operand:DF 4 "memory_operand" "m"))])]
  ""
- "b %z2"
+ "b %2"
  [(set_attr "type" "branch")
   (set_attr "length" "4")])
 
 }"
   [(set_attr "type" "load")])
 \f
+(define_insn "bpermd_<mode>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "r")
+                  (match_operand:P 2 "gpc_reg_operand" "r")] UNSPEC_BPERM))]
+  "TARGET_POPCNTD"
+  "bpermd %0,%1,%2"
+  [(set_attr "type" "integer")])
+
+\f
+;; Builtin fma support.  Handle 
+;; Note that the conditions for expansion are in the FMA_F iterator.
+
+(define_expand "fma<mode>4"
+  [(set (match_operand:FMA_F 0 "register_operand" "")
+       (fma:FMA_F
+         (match_operand:FMA_F 1 "register_operand" "")
+         (match_operand:FMA_F 2 "register_operand" "")
+         (match_operand:FMA_F 3 "register_operand" "")))]
+  ""
+  "")
+
+; Altivec only has fma and nfms.
+(define_expand "fms<mode>4"
+  [(set (match_operand:FMA_F 0 "register_operand" "")
+       (fma:FMA_F
+         (match_operand:FMA_F 1 "register_operand" "")
+         (match_operand:FMA_F 2 "register_operand" "")
+         (neg:FMA_F (match_operand:FMA_F 3 "register_operand" ""))))]
+  "!VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+  "")
+
+;; If signed zeros are ignored, -(a * b - c) = -a * b + c.
+(define_expand "fnma<mode>4"
+  [(set (match_operand:FMA_F 0 "register_operand" "")
+       (neg:FMA_F
+         (fma:FMA_F
+           (match_operand:FMA_F 1 "register_operand" "")
+           (match_operand:FMA_F 2 "register_operand" "")
+           (neg:FMA_F (match_operand:FMA_F 3 "register_operand" "")))))]
+  "!HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "")
+
+;; If signed zeros are ignored, -(a * b + c) = -a * b - c.
+(define_expand "fnms<mode>4"
+  [(set (match_operand:FMA_F 0 "register_operand" "")
+       (neg:FMA_F
+         (fma:FMA_F
+           (match_operand:FMA_F 1 "register_operand" "")
+           (match_operand:FMA_F 2 "register_operand" "")
+           (match_operand:FMA_F 3 "register_operand" ""))))]
+  "!HONOR_SIGNED_ZEROS (<MODE>mode) && !VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+  "")
+
+; Not an official optab name, but used from builtins.
+(define_expand "nfma<mode>4"
+  [(set (match_operand:FMA_F 0 "register_operand" "")
+       (neg:FMA_F
+         (fma:FMA_F
+           (match_operand:FMA_F 1 "register_operand" "")
+           (match_operand:FMA_F 2 "register_operand" "")
+           (match_operand:FMA_F 3 "register_operand" ""))))]
+  "!VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+  "")
+
+; Not an official optab name, but used from builtins.
+(define_expand "nfms<mode>4"
+  [(set (match_operand:FMA_F 0 "register_operand" "")
+       (neg:FMA_F
+         (fma:FMA_F
+           (match_operand:FMA_F 1 "register_operand" "")
+           (match_operand:FMA_F 2 "register_operand" "")
+           (neg:FMA_F (match_operand:FMA_F 3 "register_operand" "")))))]
+  ""
+  "")
+
+\f
 
 (include "sync.md")
+(include "vector.md")
+(include "vsx.md")
 (include "altivec.md")
 (include "spe.md")
 (include "dfp.md")