diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9e3f1a7..b108c01 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,24 @@
+2011-10-04  David S. Miller  <davem@davemloft.net>
+
+	* config/sparc/sparc.md (UNSPEC_FHADD, UNSPEC_FHSUB,
+	UNSPEC_XMUL): New unspecs.
+	(muldi3_v8plus): Use output_v8plus_mult.
+	(*naddsf3, *nadddf3, *nmulsf3, *nmuldf3, *nmuldf3_extend):
+	New VIS 3.0 combiner patterns.
+	(fhaddsf_vis, fhadddf_vis, fhsubsf_vis, fhsubdf_vis,
+	fnhaddsf_vis, fnhaddf_vis, umulxhi_vis, *umulxhi_sp64,
+	umulxhi_v8plus, xmulx_vis, *xmulx_sp64, xmulx_v8plus,
+	xmulxhi_vis, *xmulxhi_sp64, xmulxhi_v8plus): New VIS 3.0
+	builtins patterns.
+	* config/sparc/sparc.c (sparc_vis_init_builtins): Emit new
+	builtins.
+	(output_v8plus_mult): New function.
+	* config/sparc/sparc-protos.h: Declare it.
+	* config/sparc/visintrin.h (__vis_fhadds, __vis_fhaddd,
+	__vis_fhsubs, __vis_fhsubd, __vis_fnhadds, __vis_fnhaddd,
+	__vis_umulxhi, __vis_xmulx, __vis_xmulxhi): New intrinsics.
+	* doc/extend.texi: Document new builtins.
+
 2011-10-04  Richard Henderson  <rth@redhat.com>
 
 	* c-typeck.c (c_build_vec_shuffle_expr): Fix uninitialized variable.
diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h
index dfa461a..f7b563e 100644
--- a/gcc/config/sparc/sparc-protos.h
+++ b/gcc/config/sparc/sparc-protos.h
@@ -105,6 +105,7 @@ extern int v9_regcmp_p (enum rtx_code);
 extern int sparc_check_64 (rtx, rtx);
 extern rtx gen_df_reg (rtx, int);
 extern void sparc_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
+extern const char *output_v8plus_mult (rtx, rtx *, const char *);
 #endif /* RTX_CODE */
 
 #endif /* __SPARC_PROTOS_H__ */
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 5e67b4c..b2cbdd2 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -9236,6 +9236,12 @@ sparc_vis_init_builtins (void)
 						 void_type_node, 0);
   tree void_ftype_si = build_function_type_list (void_type_node,
 						 intSI_type_node, 0);
+  tree sf_ftype_sf_sf = build_function_type_list (float_type_node,
+						  float_type_node,
+						  float_type_node, 0);
+  tree df_ftype_df_df = build_function_type_list (double_type_node,
+						  double_type_node,
+						  double_type_node, 0);
 
   /* Packing and expanding vectors.  */
   def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis,
@@ -9552,6 +9558,26 @@ sparc_vis_init_builtins (void)
 	  def_builtin_const ("__builtin_vis_fucmpeq8", CODE_FOR_fucmpeq8si_vis,
 			     si_ftype_v8qi_v8qi);
 	}
+
+      def_builtin_const ("__builtin_vis_fhadds", CODE_FOR_fhaddsf_vis,
+			 sf_ftype_sf_sf);
+      def_builtin_const ("__builtin_vis_fhaddd", CODE_FOR_fhadddf_vis,
+			 df_ftype_df_df);
+      def_builtin_const ("__builtin_vis_fhsubs", CODE_FOR_fhsubsf_vis,
+			 sf_ftype_sf_sf);
+      def_builtin_const ("__builtin_vis_fhsubd", CODE_FOR_fhsubdf_vis,
+			 df_ftype_df_df);
+      def_builtin_const ("__builtin_vis_fnhadds", CODE_FOR_fnhaddsf_vis,
+			 sf_ftype_sf_sf);
+      def_builtin_const ("__builtin_vis_fnhaddd", CODE_FOR_fnhadddf_vis,
+			 df_ftype_df_df);
+
+      def_builtin_const ("__builtin_vis_umulxhi", CODE_FOR_umulxhi_vis,
+			 di_ftype_di_di);
+      def_builtin_const ("__builtin_vis_xmulx", CODE_FOR_xmulx_vis,
+			 di_ftype_di_di);
+      def_builtin_const ("__builtin_vis_xmulxhi", CODE_FOR_xmulxhi_vis,
+			 di_ftype_di_di);
     }
 }
 
@@ -10738,4 +10764,77 @@ sparc_preferred_reload_class (rtx x, reg_class_t rclass)
   return rclass;
 }
 
+const char *
+output_v8plus_mult (rtx insn, rtx *operands, const char *name)
+{
+  char mulstr[32];
+
+  gcc_assert (! TARGET_ARCH64);
+
+  if (sparc_check_64 (operands[1], insn) <= 0)
+    output_asm_insn ("srl\t%L1, 0, %L1", operands);
+  if (which_alternative == 1)
+    output_asm_insn ("sllx\t%H1, 32, %H1", operands);
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if (which_alternative == 1)
+	{
+	  output_asm_insn ("or\t%L1, %H1, %H1", operands);
+	  sprintf (mulstr, "%s\t%%H1, %%2, %%L0", name);
+	  output_asm_insn (mulstr, operands);
+	  return "srlx\t%L0, 32, %H0";
+	}
+      else
+	{
+	  output_asm_insn ("sllx\t%H1, 32, %3", operands);
+          output_asm_insn ("or\t%L1, %3, %3", operands);
+          sprintf (mulstr, "%s\t%%3, %%2, %%3", name);
+	  output_asm_insn (mulstr, operands);
+	  output_asm_insn ("srlx\t%3, 32, %H0", operands);
+          return "mov\t%3, %L0";
+	}
+    }
+  else if (rtx_equal_p (operands[1], operands[2]))
+    {
+      if (which_alternative == 1)
+	{
+	  output_asm_insn ("or\t%L1, %H1, %H1", operands);
+          sprintf (mulstr, "%s\t%%H1, %%H1, %%L0", name);
+	  output_asm_insn (mulstr, operands);
+	  return "srlx\t%L0, 32, %H0";
+	}
+      else
+	{
+	  output_asm_insn ("sllx\t%H1, 32, %3", operands);
+          output_asm_insn ("or\t%L1, %3, %3", operands);
+	  sprintf (mulstr, "%s\t%%3, %%3, %%3", name);
+	  output_asm_insn (mulstr, operands);
+	  output_asm_insn ("srlx\t%3, 32, %H0", operands);
+          return "mov\t%3, %L0";
+	}
+    }
+  if (sparc_check_64 (operands[2], insn) <= 0)
+    output_asm_insn ("srl\t%L2, 0, %L2", operands);
+  if (which_alternative == 1)
+    {
+      output_asm_insn ("or\t%L1, %H1, %H1", operands);
+      output_asm_insn ("sllx\t%H2, 32, %L1", operands);
+      output_asm_insn ("or\t%L2, %L1, %L1", operands);
+      sprintf (mulstr, "%s\t%%H1, %%L1, %%L0", name);
+      output_asm_insn (mulstr, operands);
+      return "srlx\t%L0, 32, %H0";
+    }
+  else
+    {
+      output_asm_insn ("sllx\t%H1, 32, %3", operands);
+      output_asm_insn ("sllx\t%H2, 32, %4", operands);
+      output_asm_insn ("or\t%L1, %3, %3", operands);
+      output_asm_insn ("or\t%L2, %4, %4", operands);
+      sprintf (mulstr, "%s\t%%3, %%4, %%3", name);
+      output_asm_insn (mulstr, operands);
+      output_asm_insn ("srlx\t%3, 32, %H0", operands);
+      return "mov\t%3, %L0";
+    }
+}
+
 #include "gt-sparc.h"
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 92ec3a6..e491aa1 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -86,6 +86,9 @@
    (UNSPEC_FCHKSM16		80)
    (UNSPEC_PDISTN		81)
    (UNSPEC_FUCMP		82)
+   (UNSPEC_FHADD		83)
+   (UNSPEC_FHSUB		84)
+   (UNSPEC_XMUL			85)
   ])
 
 (define_constants
@@ -4012,32 +4015,7 @@
    (clobber (match_scratch:SI 3 "=&h,X"))
    (clobber (match_scratch:SI 4 "=&h,X"))]
   "TARGET_V8PLUS"
-{
-  if (sparc_check_64 (operands[1], insn) <= 0)
-    output_asm_insn ("srl\t%L1, 0, %L1", operands);
-  if (which_alternative == 1)
-    output_asm_insn ("sllx\t%H1, 32, %H1", operands);
-  if (GET_CODE (operands[2]) == CONST_INT)
-    {
-      if (which_alternative == 1)
-	return "or\t%L1, %H1, %H1\n\tmulx\t%H1, %2, %L0\;srlx\t%L0, 32, %H0";
-      else
-	return "sllx\t%H1, 32, %3\n\tor\t%L1, %3, %3\n\tmulx\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0";
-    }
-  else if (rtx_equal_p (operands[1], operands[2]))
-    {
-      if (which_alternative == 1)
-	return "or\t%L1, %H1, %H1\n\tmulx\t%H1, %H1, %L0\;srlx\t%L0, 32, %H0";
-      else
-	return "sllx\t%H1, 32, %3\n\tor\t%L1, %3, %3\n\tmulx\t%3, %3, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0";
-    }
-  if (sparc_check_64 (operands[2], insn) <= 0)
-    output_asm_insn ("srl\t%L2, 0, %L2", operands);
-  if (which_alternative == 1)
-    return "or\t%L1, %H1, %H1\n\tsllx\t%H2, 32, %L1\n\tor\t%L2, %L1, %L1\n\tmulx\t%H1, %L1, %L0\;srlx\t%L0, 32, %H0";
-  else
-    return "sllx\t%H1, 32, %3\n\tsllx\t%H2, 32, %4\n\tor\t%L1, %3, %3\n\tor\t%L2, %4, %4\n\tmulx\t%3, %4, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0";
-}
+  "* return output_v8plus_mult (insn, operands, \"mulx\");"
   [(set_attr "type" "multi")
    (set_attr "length" "9,8")])
 
@@ -8407,4 +8385,247 @@
   "TARGET_VIS3"
   "fucmp<code>8\t%1, %2, %0")
 
+(define_insn "*naddsf3"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (neg:SF (plus:SF (match_operand:SF 1 "register_operand" "f")
+                         (match_operand:SF 2 "register_operand" "f"))))]
+  "TARGET_VIS3"
+  "fnadds\t%1, %2, %0"
+  [(set_attr "type" "fp")])
+
+(define_insn "*nadddf3"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (neg:DF (plus:DF (match_operand:DF 1 "register_operand" "e")
+                         (match_operand:DF 2 "register_operand" "e"))))]
+  "TARGET_VIS3"
+  "fnaddd\t%1, %2, %0"
+  [(set_attr "type" "fp")
+   (set_attr "fptype" "double")])
+
+(define_insn "*nmulsf3"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (mult:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
+                 (match_operand:SF 2 "register_operand" "f")))]
+  "TARGET_VIS3"
+  "fnmuls\t%1, %2, %0"
+  [(set_attr "type" "fpmul")])
+
+(define_insn "*nmuldf3"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (mult:DF (neg:DF (match_operand:DF 1 "register_operand" "e"))
+                 (match_operand:DF 2 "register_operand" "e")))]
+  "TARGET_VIS3"
+  "fnmuld\t%1, %2, %0"
+  [(set_attr "type" "fpmul")
+   (set_attr "fptype" "double")])
+
+(define_insn "*nmuldf3_extend"
+  [(set (match_operand:DF 0 "register_operand" "=e")
+        (mult:DF (neg:DF (float_extend:DF
+                           (match_operand:SF 1 "register_operand" "f")))
+                 (float_extend:DF
+                   (match_operand:SF 2 "register_operand" "f"))))]
+  "TARGET_VIS3"
+  "fnsmuld\t%1, %2, %0"
+  [(set_attr "type" "fpmul")
+   (set_attr "fptype" "double")])
+
+(define_insn "fhaddsf_vis"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (unspec:SF [(match_operand:SF 1 "register_operand" "f")
+                    (match_operand:SF 2 "register_operand" "f")]
+                   UNSPEC_FHADD))]
+  "TARGET_VIS3"
+  "fhadds\t%1, %2, %0"
+  [(set_attr "type" "fp")])
+
+(define_insn "fhadddf_vis"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+        (unspec:DF [(match_operand:DF 1 "register_operand" "f")
+                    (match_operand:DF 2 "register_operand" "f")]
+                   UNSPEC_FHADD))]
+  "TARGET_VIS3"
+  "fhaddd\t%1, %2, %0"
+  [(set_attr "type" "fp")
+   (set_attr "fptype" "double")])
+
+(define_insn "fhsubsf_vis"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (unspec:SF [(match_operand:SF 1 "register_operand" "f")
+                    (match_operand:SF 2 "register_operand" "f")]
+                   UNSPEC_FHSUB))]
+  "TARGET_VIS3"
+  "fhsubs\t%1, %2, %0"
+  [(set_attr "type" "fp")])
+
+(define_insn "fhsubdf_vis"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+        (unspec:DF [(match_operand:DF 1 "register_operand" "f")
+                    (match_operand:DF 2 "register_operand" "f")]
+                   UNSPEC_FHSUB))]
+  "TARGET_VIS3"
+  "fhsubd\t%1, %2, %0"
+  [(set_attr "type" "fp")
+   (set_attr "fptype" "double")])
+
+(define_insn "fnhaddsf_vis"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (neg:SF (unspec:SF [(match_operand:SF 1 "register_operand" "f")
+                            (match_operand:SF 2 "register_operand" "f")]
+                           UNSPEC_FHADD)))]
+  "TARGET_VIS3"
+  "fnhadds\t%1, %2, %0"
+  [(set_attr "type" "fp")])
+
+(define_insn "fnhadddf_vis"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+        (neg:DF (unspec:DF [(match_operand:DF 1 "register_operand" "f")
+                            (match_operand:DF 2 "register_operand" "f")]
+                           UNSPEC_FHADD)))]
+  "TARGET_VIS3"
+  "fnhaddd\t%1, %2, %0"
+  [(set_attr "type" "fp")
+   (set_attr "fptype" "double")])
+
+(define_expand "umulxhi_vis"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (truncate:DI
+          (lshiftrt:TI
+            (mult:TI (zero_extend:TI
+                       (match_operand:DI 1 "arith_operand" ""))
+                     (zero_extend:TI
+                       (match_operand:DI 2 "arith_operand" "")))
+           (const_int 64))))]
+ "TARGET_VIS3"
+{
+  if (! TARGET_ARCH64)
+    {
+      emit_insn (gen_umulxhi_v8plus (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+})
+
+(define_insn "*umulxhi_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (truncate:DI
+          (lshiftrt:TI
+            (mult:TI (zero_extend:TI
+                       (match_operand:DI 1 "arith_operand" "%r"))
+                     (zero_extend:TI
+                       (match_operand:DI 2 "arith_operand" "rI")))
+           (const_int 64))))]
+  "TARGET_VIS3 && TARGET_ARCH64"
+  "umulxhi\t%1, %2, %0"
+  [(set_attr "type" "imul")])
+
+(define_insn "umulxhi_v8plus"
+  [(set (match_operand:DI 0 "register_operand" "=r,h")
+        (truncate:DI
+          (lshiftrt:TI
+            (mult:TI (zero_extend:TI
+                       (match_operand:DI 1 "arith_operand" "%r,0"))
+                     (zero_extend:TI
+                       (match_operand:DI 2 "arith_operand" "rI,rI")))
+           (const_int 64))))
+   (clobber (match_scratch:SI 3 "=&h,X"))
+   (clobber (match_scratch:SI 4 "=&h,X"))]
+  "TARGET_VIS3 && ! TARGET_ARCH64"
+  "* return output_v8plus_mult (insn, operands, \"umulxhi\");"
+  [(set_attr "type" "imul")
+   (set_attr "length" "9,8")])
+
+(define_expand "xmulx_vis"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (truncate:DI
+          (unspec:TI [(zero_extend:TI
+                        (match_operand:DI 1 "arith_operand" ""))
+                      (zero_extend:TI
+                        (match_operand:DI 2 "arith_operand" ""))]
+           UNSPEC_XMUL)))]
+  "TARGET_VIS3"
+{
+  if (! TARGET_ARCH64)
+    {
+      emit_insn (gen_xmulx_v8plus (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+})
+
+(define_insn "*xmulx_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (truncate:DI
+          (unspec:TI [(zero_extend:TI
+                        (match_operand:DI 1 "arith_operand" "%r"))
+                      (zero_extend:TI
+                        (match_operand:DI 2 "arith_operand" "rI"))]
+           UNSPEC_XMUL)))]
+  "TARGET_VIS3 && TARGET_ARCH64"
+  "xmulx\t%1, %2, %0"
+  [(set_attr "type" "imul")])
+
+(define_insn "xmulx_v8plus"
+  [(set (match_operand:DI 0 "register_operand" "=r,h")
+        (truncate:DI
+          (unspec:TI [(zero_extend:TI
+                        (match_operand:DI 1 "arith_operand" "%r,0"))
+                      (zero_extend:TI
+                        (match_operand:DI 2 "arith_operand" "rI,rI"))]
+           UNSPEC_XMUL)))
+   (clobber (match_scratch:SI 3 "=&h,X"))
+   (clobber (match_scratch:SI 4 "=&h,X"))]
+  "TARGET_VIS3 && ! TARGET_ARCH64"
+  "* return output_v8plus_mult (insn, operands, \"xmulx\");"
+  [(set_attr "type" "imul")
+   (set_attr "length" "9,8")])
+
+(define_expand "xmulxhi_vis"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (truncate:DI
+          (lshiftrt:TI
+            (unspec:TI [(zero_extend:TI
+                          (match_operand:DI 1 "arith_operand" ""))
+                        (zero_extend:TI
+                          (match_operand:DI 2 "arith_operand" ""))]
+             UNSPEC_XMUL)
+           (const_int 64))))]
+  "TARGET_VIS3"
+{
+  if (! TARGET_ARCH64)
+    {
+      emit_insn (gen_xmulxhi_v8plus (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+})
+
+(define_insn "*xmulxhi_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (truncate:DI
+          (lshiftrt:TI
+            (unspec:TI [(zero_extend:TI
+                          (match_operand:DI 1 "arith_operand" "%r"))
+                        (zero_extend:TI
+                          (match_operand:DI 2 "arith_operand" "rI"))]
+             UNSPEC_XMUL)
+           (const_int 64))))]
+  "TARGET_VIS3 && TARGET_ARCH64"
+  "xmulxhi\t%1, %2, %0"
+  [(set_attr "type" "imul")])
+
+(define_insn "xmulxhi_v8plus"
+  [(set (match_operand:DI 0 "register_operand" "=r,h")
+        (truncate:DI
+          (lshiftrt:TI
+            (unspec:TI [(zero_extend:TI
+                          (match_operand:DI 1 "arith_operand" "%r,0"))
+                        (zero_extend:TI
+                          (match_operand:DI 2 "arith_operand" "rI,rI"))]
+             UNSPEC_XMUL)
+           (const_int 64))))
+   (clobber (match_scratch:SI 3 "=&h,X"))
+   (clobber (match_scratch:SI 4 "=&h,X"))]
+  "TARGET_VIS3 && !TARGET_ARCH64"
+  "* return output_v8plus_mult (insn, operands, \"xmulxhi\");"
+  [(set_attr "type" "imul")
+   (set_attr "length" "9,8")])
+
 (include "sync.md")
diff --git a/gcc/config/sparc/visintrin.h b/gcc/config/sparc/visintrin.h
index 32e44e5..deb68b4 100644
--- a/gcc/config/sparc/visintrin.h
+++ b/gcc/config/sparc/visintrin.h
@@ -627,4 +627,67 @@ __vis_fucmpeq8 (__v8qi __A, __v8qi __B)
   return __builtin_vis_fucmpeq8 (__A, __B);
 }
 
+extern __inline float
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_fhadds (float __A, float __B)
+{
+  return __builtin_vis_fhadds (__A, __B);
+}
+
+extern __inline double
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_fhaddd (double __A, double __B)
+{
+  return __builtin_vis_fhaddd (__A, __B);
+}
+
+extern __inline float
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_fhsubs (float __A, float __B)
+{
+  return __builtin_vis_fhsubs (__A, __B);
+}
+
+extern __inline double
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_fhsubd (double __A, double __B)
+{
+  return __builtin_vis_fhsubd (__A, __B);
+}
+
+extern __inline float
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_fnhadds (float __A, float __B)
+{
+  return __builtin_vis_fnhadds (__A, __B);
+}
+
+extern __inline double
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_fnhaddd (double __A, double __B)
+{
+  return __builtin_vis_fnhaddd (__A, __B);
+}
+
+extern __inline __i64
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_umulxhi (__i64 __A, __i64 __B)
+{
+  return __builtin_vis_umulxhi (__A, __B);
+}
+
+extern __inline __i64
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_xmulx (__i64 __A, __i64 __B)
+{
+  return __builtin_vis_xmulx (__A, __B);
+}
+
+extern __inline __i64
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+__vis_xmulxhi (__i64 __A, __i64 __B)
+{
+  return __builtin_vis_xmulxhi (__A, __B);
+}
+
 #endif  /* _VISINTRIN_H_INCLUDED */
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 20ee772..c3ebf09 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13099,6 +13099,17 @@ long __builtin_vis_fucmple8 (v8qi, v8qi);
 long __builtin_vis_fucmpne8 (v8qi, v8qi);
 long __builtin_vis_fucmpgt8 (v8qi, v8qi);
 long __builtin_vis_fucmpeq8 (v8qi, v8qi);
+
+float __builtin_vis_fhadds (float, float);
+double __builtin_vis_fhaddd (double, double);
+float __builtin_vis_fhsubs (float, float);
+double __builtin_vis_fhsubd (double, double);
+float __builtin_vis_fnhadds (float, float);
+double __builtin_vis_fnhaddd (double, double);
+
+int64_t __builtin_vis_umulxhi (int64_t, int64_t);
+int64_t __builtin_vis_xmulx (int64_t, int64_t);
+int64_t __builtin_vis_xmulxhi (int64_t, int64_t);
 @end smallexample
 
 @node SPU Built-in Functions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b6b02a2..878ff73 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2011-10-04  David S. Miller  <davem@davemloft.net>
+
+	* gcc.target/sparc/fhalve.c: New test.
+	* gcc.target/sparc/fnegop.c: New test.
+	* gcc.target/sparc/xmul.c: New test.
+
 2011-10-04  Janus Weil  <janus@gcc.gnu.org>
 
 	PR fortran/35831
diff --git a/gcc/testsuite/gcc.target/sparc/fhalve.c b/gcc/testsuite/gcc.target/sparc/fhalve.c
new file mode 100644
index 0000000..340b936
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/fhalve.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-mcpu=niagara3 -mvis" } */
+
+float test_fhadds (float x, float y)
+{
+  return __builtin_vis_fhadds (x, y);
+}
+
+double test_fhaddd (double x, double y)
+{
+  return __builtin_vis_fhaddd (x, y);
+}
+
+float test_fhsubs (float x, float y)
+{
+  return __builtin_vis_fhsubs (x, y);
+}
+
+double test_fhsubd (double x, double y)
+{
+  return __builtin_vis_fhsubd (x, y);
+}
+
+float test_fnhadds (float x, float y)
+{
+  return __builtin_vis_fnhadds (x, y);
+}
+
+double test_fnhaddd (double x, double y)
+{
+  return __builtin_vis_fnhaddd (x, y);
+}
+
+/* { dg-final { scan-assembler "fhadds\t%" } } */
+/* { dg-final { scan-assembler "fhaddd\t%" } } */
+/* { dg-final { scan-assembler "fhsubs\t%" } } */
+/* { dg-final { scan-assembler "fhsubd\t%" } } */
+/* { dg-final { scan-assembler "fnhadds\t%" } } */
+/* { dg-final { scan-assembler "fnhaddd\t%" } } */
diff --git a/gcc/testsuite/gcc.target/sparc/fnegop.c b/gcc/testsuite/gcc.target/sparc/fnegop.c
new file mode 100644
index 0000000..25f8c19
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/fnegop.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcpu=niagara3 -mvis" } */
+
+float test_fnadds(float x, float y)
+{
+  return -(x + y);
+}
+
+double test_fnaddd(double x, double y)
+{
+  return -(x + y);
+}
+
+float test_fnmuls(float x, float y)
+{
+  return -(x * y);
+}
+
+double test_fnmuld(double x, double y)
+{
+  return -(x * y);
+}
+
+double test_fnsmuld(float x, float y)
+{
+  return -((double)x * (double)y);
+}
+
+/* { dg-final { scan-assembler "fnadds\t%" } } */
+/* { dg-final { scan-assembler "fnaddd\t%" } } */
+/* { dg-final { scan-assembler "fnmuls\t%" } } */
+/* { dg-final { scan-assembler "fnmuld\t%" } } */
+/* { dg-final { scan-assembler "fnsmuld\t%" } } */
diff --git a/gcc/testsuite/gcc.target/sparc/xmul.c b/gcc/testsuite/gcc.target/sparc/xmul.c
new file mode 100644
index 0000000..ce80e6c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/xmul.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-mcpu=niagara3 -mvis" } */
+typedef long long int64_t;
+
+int64_t test_umulxhi (int64_t x, int64_t y)
+{
+  return __builtin_vis_umulxhi (x, y);
+}
+
+int64_t test_xmulx (int64_t x, int64_t y)
+{
+  return __builtin_vis_xmulx (x, y);
+}
+
+int64_t test_xmulxhi (int64_t x, int64_t y)
+{
+  return __builtin_vis_xmulxhi (x, y);
+}
+
+/* { dg-final { scan-assembler "umulxhi\t%" } } */
+/* { dg-final { scan-assembler "xmulx\t%" } } */
+/* { dg-final { scan-assembler "xmulxhi\t%" } } */
