Index: gcc/config/rs6000/vector.md
===================================================================
--- gcc/config/rs6000/vector.md	(revision 166510)
+++ gcc/config/rs6000/vector.md	(working copy)
@@ -233,6 +233,38 @@ (define_expand "neg<mode>2"
     }
 }")
 
+(define_expand "fma<mode>4"
+  [(set (match_operand:VEC_F 0 "vfloat_operand" "")
+	(fma:VEC_F (match_operand:VEC_F 1 "vfloat_operand" "")
+		   (match_operand:VEC_F 2 "vfloat_operand" "")
+		   (match_operand:VEC_F 3 "vfloat_operand" "")))]
+  "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
+  "")
+
+(define_expand "fms<mode>4"
+  [(set (match_operand:VEC_F 0 "vfloat_operand" "")
+	(fma:VEC_F (match_operand:VEC_F 1 "vfloat_operand" "")
+		   (match_operand:VEC_F 2 "vfloat_operand" "")
+		   (neg:VEC_F (match_operand:VEC_F 3 "vfloat_operand" ""))))]
+  "VECTOR_UNIT_VSX_P (<MODE>mode)"
+  "")
+
+(define_expand "fnma<mode>4"
+  [(set (match_operand:VEC_F 0 "vfloat_operand" "")
+	(fma:VEC_F (neg:VEC_F (match_operand:VEC_F 1 "vfloat_operand" ""))
+		   (match_operand:VEC_F 2 "vfloat_operand" "")
+		   (match_operand:VEC_F 3 "vfloat_operand" "")))]
+  "VECTOR_UNIT_VSX_P (<MODE>mode) && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "")
+
+(define_expand "fnms<mode>4"
+  [(set (match_operand:VEC_F 0 "vfloat_operand" "")
+	(fma:VEC_F (neg:VEC_F (match_operand:VEC_F 1 "vfloat_operand" ""))
+		   (match_operand:VEC_F 2 "vfloat_operand" "")
+		   (neg:VEC_F (match_operand:VEC_F 3 "vfloat_operand" ""))))]
+  "VECTOR_UNIT_VSX_P (<MODE>mode) && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "")
+
 (define_expand "abs<mode>2"
   [(set (match_operand:VEC_F 0 "vfloat_operand" "")
 	(abs:VEC_F (match_operand:VEC_F 1 "vfloat_operand" "")))]
Index: gcc/config/rs6000/rs6000.opt
===================================================================
--- gcc/config/rs6000/rs6000.opt	(revision 166510)
+++ gcc/config/rs6000/rs6000.opt	(working copy)
@@ -177,8 +177,8 @@ Target Report Var(TARGET_AVOID_XFORM) In
 Avoid generation of indexed load/store instructions when possible
 
 mfused-madd
-Target Report Var(TARGET_FUSED_MADD) Init(1)
-Generate fused multiply/add instructions
+Target Alias(ffp-contract=, fast, off)
+Generate fused multiply/add instructions.  Same as -ffp-contract=fast
 
 mtls-markers
 Target Report Var(tls_markers) Init(1)
Index: gcc/config/rs6000/vsx.md
===================================================================
--- gcc/config/rs6000/vsx.md	(revision 166510)
+++ gcc/config/rs6000/vsx.md	(working copy)
@@ -666,6 +666,23 @@ (define_insn "vsx_fnmadd<mode>4_2"
   [(set_attr "type" "<VStype_mul>")
    (set_attr "fp_type" "<VSfptype_mul>")])
 
+(define_insn "*vsx_fnmadd<mode>4_3"
+  [(set (match_operand:VSX_B 0 "vsx_register_operand" "=<VSr>,<VSr>,?wa,?wa")
+	(fma:VSX_B
+	 (neg:VSX_B
+	  (match_operand:VSX_B 1 "vsx_register_operand" "%<VSr>,<VSr>,wa,wa"))
+	 (match_operand:VSX_B 2 "vsx_register_operand" "<VSr>,0,wa,0")
+	 (neg:VSX_B
+	  (match_operand:VSX_B 3 "vsx_register_operand" "0,<VSr>,0,wa"))))]
+  "VECTOR_UNIT_VSX_P (<MODE>mode) && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "@
+   x<VSv>nmadda<VSs> %x0,%x1,%x2
+   x<VSv>nmaddm<VSs> %x0,%x1,%x3
+   x<VSv>nmadda<VSs> %x0,%x1,%x2
+   x<VSv>nmaddm<VSs> %x0,%x1,%x3"
+  [(set_attr "type" "<VStype_mul>")
+   (set_attr "fp_type" "<VSfptype_mul>")])
+
 (define_insn "vsx_fnmsub<mode>4"
   [(set (match_operand:VSX_B 0 "vsx_register_operand" "=<VSr>,<VSr>,?wa,?wa")
 	(neg:VSX_B
@@ -717,6 +734,22 @@ (define_insn "vsx_fnmsub<mode>4_2"
   [(set_attr "type" "<VStype_mul>")
    (set_attr "fp_type" "<VSfptype_mul>")])
 
+(define_insn "*vsx_fnmsub<mode>4_3"
+  [(set (match_operand:VSX_B 0 "vsx_register_operand" "=<VSr>,<VSr>,?wa,?wa")
+	 (fma:VSX_B
+	  (neg:VSX_B
+	   (match_operand:VSX_B 1 "vsx_register_operand" "<VSr>,<VSr>,wa,wa"))
+	  (match_operand:VSX_B 2 "vsx_register_operand" "<VSr>,0,wa,0")
+	  (match_operand:VSX_B 3 "vsx_register_operand" "0,<VSr>,0,wa")))]
+  "VECTOR_UNIT_VSX_P (<MODE>mode) && !HONOR_SIGNED_ZEROS (<MODE>mode)"
+  "@
+   x<VSv>nmsuba<VSs> %x0,%x1,%x2
+   x<VSv>nmsubm<VSs> %x0,%x1,%x3
+   x<VSv>nmsuba<VSs> %x0,%x1,%x2
+   x<VSv>nmsubm<VSs> %x0,%x1,%x3"
+  [(set_attr "type" "<VStype_mul>")
+   (set_attr "fp_type" "<VSfptype_mul>")])
+
 ;; Vector conditional expressions (no scalar version for these instructions)
 (define_insn "vsx_eq<mode>"
   [(set (match_operand:VSX_F 0 "vsx_register_operand" "=<VSr>,?wa")
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 166510)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -597,6 +597,9 @@ extern int rs6000_vector_align[];
 			 && TARGET_DOUBLE_FLOAT \
 			 && (TARGET_PPC_GFXOPT || VECTOR_UNIT_VSX_P (DFmode)))
 
+/* Old -mno-fused-add is now -ffp-contract=off.  */
+#define TARGET_FUSED_MADD (flag_fp_contract_mode != FP_CONTRACT_OFF)
+
 /* Whether the various reciprocal divide/square root estimate instructions
    exist, and whether we should automatically generate code for the instruction
    by default.  */
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 166510)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -5870,7 +5870,7 @@ (define_insn "fmasf4_fpr"
   [(set_attr "type" "fp")
    (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn "*fmssf4_fpr"
+(define_insn "fmssf4"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
 	(fma:SF (match_operand:SF 1 "gpc_reg_operand" "f")
 		(match_operand:SF 2 "gpc_reg_operand" "f")
@@ -5885,7 +5885,28 @@ (define_insn "*fmssf4_fpr"
   [(set_attr "type" "fp")
    (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn "*fnmasf4_fpr"
+;; Note, FNMA is defined to be (-a * b) + c, and FNMS is defined to be
+;; (-a * b) - c.  The PowerPC defines its FNMADD operation as -((a*b)+c)
+;; and FNMSUB as -((a*b)-c), so for FNMA we need to emit a FNMSUB and for
+;; FNMS we need to emit a FNMADD.  And signed zeros are also a possiblity
+;; so make this fast-math only
+(define_insn "fnmasf4"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+	(fma: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_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+   && !HONOR_SIGNED_ZEROS (SFmode)"
+  "*
+{
+  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_insn "*fnmasf4_2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
 	(neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f")
 			(match_operand:SF 2 "gpc_reg_operand" "f")
@@ -5900,7 +5921,23 @@ (define_insn "*fnmasf4_fpr"
   [(set_attr "type" "fp")
    (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn "*fnmssf4_fpr"
+(define_insn "fnmssf4"
+  [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+	(fma:SF (neg: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
+   && !HONOR_SIGNED_ZEROS (SFmode)"
+  "*
+{
+  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 "*fnmssf4_2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
 	(neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f")
 			(match_operand:SF 2 "gpc_reg_operand" "f")
@@ -6396,43 +6433,96 @@ (define_expand "fmadf4"
   "")
 
 (define_insn "fmadf4_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-	(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")))]
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(fma:DF (match_operand:DF 1 "gpc_reg_operand" "d")
+		(match_operand:DF 2 "gpc_reg_operand" "d")
+		(match_operand:DF 3 "gpc_reg_operand" "d")))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
    && VECTOR_UNIT_NONE_P (DFmode)"
   "{fma|fmadd} %0,%1,%2,%3"
   [(set_attr "type" "fp")
    (set_attr "fp_type" "fp_maddsub_s")])
 
+(define_expand "fmsdf4"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "")
+	(fma:DF (match_operand:DF 1 "gpc_reg_operand" "")
+		(match_operand:DF 2 "gpc_reg_operand" "")
+		(neg:DF (match_operand:DF 3 "gpc_reg_operand" ""))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+  "")
+
 (define_insn "*fmsdf4_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-	(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"))))]
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(fma:DF (match_operand:DF 1 "gpc_reg_operand" "d")
+		(match_operand:DF 2 "gpc_reg_operand" "d")
+		(neg:DF (match_operand:DF 3 "gpc_reg_operand" "d"))))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
    && VECTOR_UNIT_NONE_P (DFmode)"
   "{fms|fmsub} %0,%1,%2,%3"
   [(set_attr "type" "fp")
    (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn "*fnmadf4_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-	(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"))))]
+;; Note, FNMA is defined to be (-a * b) + c, and FNMS is defined to be
+;; (-a * b) - c.  The PowerPC defines its FNMADD operation as -((a*b)+c)
+;; and FNMSUB as -((a*b)-c), so for FNMA we need to emit a FNMSUB and for
+;; FNMS we need to emit a FNMADD.  And signed zeros are also a possiblity
+;; so make this fast-math only
+(define_expand "fnmadf4"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "")
+	(fma:DF (neg:DF (match_operand:DF 1 "gpc_reg_operand" ""))
+		(match_operand:DF 2 "gpc_reg_operand" "")
+		(match_operand:DF 3 "gpc_reg_operand" "")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !HONOR_SIGNED_ZEROS (DFmode)"
+  "")
+
+(define_insn "*fnmadf4_fpr_1"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(fma:DF (neg:DF (match_operand:DF 1 "gpc_reg_operand" "d"))
+		(match_operand:DF 2 "gpc_reg_operand" "d")
+		(match_operand:DF 3 "gpc_reg_operand" "d")))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && VECTOR_UNIT_NONE_P (DFmode) && !HONOR_SIGNED_ZEROS (DFmode)"
+  "{fnms|fnmsub} %0,%1,%2,%3"
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
+
+(define_insn "*fnmadf4_fpr_2"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "d")
+			(match_operand:DF 2 "gpc_reg_operand" "d")
+			(match_operand:DF 3 "gpc_reg_operand" "d"))))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
    && VECTOR_UNIT_NONE_P (DFmode)"
   "{fnma|fnmadd} %0,%1,%2,%3"
   [(set_attr "type" "fp")
    (set_attr "fp_type" "fp_maddsub_s")])
 
-(define_insn "*fnmsdf4_fpr"
-  [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
-	(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")))))]
+(define_expand "fnmsdf4"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "")
+	(fma:DF (neg:DF (match_operand:DF 1 "gpc_reg_operand" ""))
+		(match_operand:DF 2 "gpc_reg_operand" "")
+		(neg:DF (match_operand:DF 3 "gpc_reg_operand" ""))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && !HONOR_SIGNED_ZEROS (DFmode)"
+  "")
+
+(define_insn "*fnmsdf4_fpr_1"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(fma:DF (neg:DF (match_operand:DF 1 "gpc_reg_operand" "d"))
+		(match_operand:DF 2 "gpc_reg_operand" "d")
+		(neg:DF (match_operand:DF 3 "gpc_reg_operand" "d"))))]
+  "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+   && VECTOR_UNIT_NONE_P (DFmode) && !HONOR_SIGNED_ZEROS (DFmode)"
+  "{fnma|fnmadd} %0,%1,%2,%3"
+  [(set_attr "type" "fp")
+   (set_attr "fp_type" "fp_maddsub_s")])
+
+(define_insn "*fnmsdf4_fpr_2"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+	(neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "d")
+			(match_operand:DF 2 "gpc_reg_operand" "d")
+			(neg:DF (match_operand:DF 3 "gpc_reg_operand" "d")))))]
   "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
    && VECTOR_UNIT_NONE_P (DFmode)"
   "{fnms|fnmsub} %0,%1,%2,%3"
