Index: config/sparc/sparc.md
===================================================================
--- config/sparc/sparc.md	(revision 205689)
+++ config/sparc/sparc.md	(working copy)
@@ -96,13 +96,19 @@ (define_c_enum "unspec" [
 
 (define_c_enum "unspecv" [
   UNSPECV_BLOCKAGE
+  UNSPECV_PROBE_STACK_RANGE
+
   UNSPECV_FLUSHW
-  UNSPECV_FLUSH
   UNSPECV_SAVEW
-  UNSPECV_CAS
-  UNSPECV_SWAP
+
+  UNSPECV_FLUSH
+
   UNSPECV_LDSTUB
-  UNSPECV_PROBE_STACK_RANGE
+  UNSPECV_SWAP
+  UNSPECV_CAS
+
+  UNSPECV_LDFSR
+  UNSPECV_STFSR
 ])
 
 (define_constants
@@ -6783,22 +6789,26 @@ (define_insn "flush_register_windows"
 
 ;; Special pattern for the FLUSH instruction.
 
-; We do SImode and DImode versions of this to quiet down genrecog's complaints
-; of the define_insn otherwise missing a mode.  We make "flush", aka
-; gen_flush, the default one since sparc_initialize_trampoline uses
-; it on SImode mem values.
-
-(define_insn "flush"
-  [(unspec_volatile [(match_operand:SI 0 "memory_operand" "m")] UNSPECV_FLUSH)]
+(define_insn "flush<P:mode>"
+  [(unspec_volatile [(match_operand:P 0 "memory_operand" "m")] UNSPECV_FLUSH)]
   ""
   { return TARGET_V9 ? "flush\t%f0" : "iflush\t%f0"; }
   [(set_attr "type" "iflush")])
 
-(define_insn "flushdi"
-  [(unspec_volatile [(match_operand:DI 0 "memory_operand" "m")] UNSPECV_FLUSH)]
-  ""
-  { return TARGET_V9 ? "flush\t%f0" : "iflush\t%f0"; }
-  [(set_attr "type" "iflush")])
+;; Special insns to load and store the 32-bit FP Status Register.
+
+(define_insn "ldfsr"
+  [(unspec_volatile [(match_operand:SI 0 "memory_operand" "m")] UNSPECV_LDFSR)]
+  "TARGET_FPU"
+  "ld\t%0, %%fsr"
+  [(set_attr "type" "load")])
+
+(define_insn "stfsr"
+  [(set (match_operand:SI 0 "memory_operand" "=m")
+        (unspec_volatile:SI [(const_int 0)] UNSPECV_STFSR))]
+  "TARGET_FPU"
+  "st\t%%fsr, %0"
+  [(set_attr "type" "store")])
 
 
 ;; Find first set instructions.
Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 205689)
+++ config/sparc/sparc.c	(working copy)
@@ -570,11 +570,11 @@ static void emit_hard_tfmode_operation (
 static bool sparc_function_ok_for_sibcall (tree, tree);
 static void sparc_init_libfuncs (void);
 static void sparc_init_builtins (void);
+static void sparc_fpu_init_builtins (void);
 static void sparc_vis_init_builtins (void);
+static tree sparc_builtin_decl (unsigned, bool);
 static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static tree sparc_fold_builtin (tree, int, tree *, bool);
-static int sparc_vis_mul8x16 (int, int);
-static void sparc_handle_vis_mul8x16 (tree *, int, tree, tree, tree);
 static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
 				   HOST_WIDE_INT, tree);
 static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT,
@@ -638,6 +638,7 @@ static reg_class_t sparc_secondary_reloa
 					   enum machine_mode,
 					   secondary_reload_info *);
 static enum machine_mode sparc_cstore_mode (enum insn_code icode);
+static void sparc_atomic_assign_expand_fenv (tree *, tree *, tree *);
 
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
 /* Table of valid machine attributes.  */
@@ -693,8 +694,6 @@ char sparc_hard_reg_printed[8];
 
 #undef TARGET_INIT_LIBFUNCS
 #define TARGET_INIT_LIBFUNCS sparc_init_libfuncs
-#undef TARGET_INIT_BUILTINS
-#define TARGET_INIT_BUILTINS sparc_init_builtins
 
 #undef TARGET_LEGITIMIZE_ADDRESS
 #define TARGET_LEGITIMIZE_ADDRESS sparc_legitimize_address
@@ -703,6 +702,10 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_MODE_DEPENDENT_ADDRESS_P
 #define TARGET_MODE_DEPENDENT_ADDRESS_P sparc_mode_dependent_address_p
 
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS sparc_init_builtins
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL sparc_builtin_decl
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN sparc_expand_builtin
 #undef TARGET_FOLD_BUILTIN
@@ -843,6 +846,9 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_CSTORE_MODE
 #define TARGET_CSTORE_MODE sparc_cstore_mode
 
+#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
+#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV sparc_atomic_assign_expand_fenv
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Return the memory reference contained in X if any, zero otherwise.  */
@@ -9237,14 +9243,14 @@ sparc32_initialize_trampoline (rtx m_tra
 
   /* On UltraSPARC a flush flushes an entire cache line.  The trampoline is
      aligned on a 16 byte boundary so one flush clears it all.  */
-  emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 0))));
+  emit_insn (gen_flushsi (validize_mem (adjust_address (m_tramp, SImode, 0))));
   if (sparc_cpu != PROCESSOR_ULTRASPARC
       && sparc_cpu != PROCESSOR_ULTRASPARC3
       && sparc_cpu != PROCESSOR_NIAGARA
       && sparc_cpu != PROCESSOR_NIAGARA2
       && sparc_cpu != PROCESSOR_NIAGARA3
       && sparc_cpu != PROCESSOR_NIAGARA4)
-    emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 8))));
+    emit_insn (gen_flushsi (validize_mem (adjust_address (m_tramp, SImode, 8))));
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
@@ -9969,15 +9975,145 @@ sparc_init_libfuncs (void)
     }
 }
 
-static tree def_builtin(const char *name, int code, tree type)
+/* SPARC builtins.  */
+enum sparc_builtins
+{
+  /* FPU builtins.  */
+  SPARC_BUILTIN_LDFSR,
+  SPARC_BUILTIN_STFSR,
+
+  /* VIS 1.0 builtins.  */
+  SPARC_BUILTIN_FPACK16,
+  SPARC_BUILTIN_FPACK32,
+  SPARC_BUILTIN_FPACKFIX,
+  SPARC_BUILTIN_FEXPAND,
+  SPARC_BUILTIN_FPMERGE,
+  SPARC_BUILTIN_FMUL8X16,
+  SPARC_BUILTIN_FMUL8X16AU,
+  SPARC_BUILTIN_FMUL8X16AL,
+  SPARC_BUILTIN_FMUL8SUX16,
+  SPARC_BUILTIN_FMUL8ULX16,
+  SPARC_BUILTIN_FMULD8SUX16,
+  SPARC_BUILTIN_FMULD8ULX16,
+  SPARC_BUILTIN_FALIGNDATAV4HI,
+  SPARC_BUILTIN_FALIGNDATAV8QI,
+  SPARC_BUILTIN_FALIGNDATAV2SI,
+  SPARC_BUILTIN_FALIGNDATADI,
+  SPARC_BUILTIN_WRGSR,
+  SPARC_BUILTIN_RDGSR,
+  SPARC_BUILTIN_ALIGNADDR,
+  SPARC_BUILTIN_ALIGNADDRL,
+  SPARC_BUILTIN_PDIST,
+  SPARC_BUILTIN_EDGE8,
+  SPARC_BUILTIN_EDGE8L,
+  SPARC_BUILTIN_EDGE16,
+  SPARC_BUILTIN_EDGE16L,
+  SPARC_BUILTIN_EDGE32,
+  SPARC_BUILTIN_EDGE32L,
+  SPARC_BUILTIN_FCMPLE16,
+  SPARC_BUILTIN_FCMPLE32,
+  SPARC_BUILTIN_FCMPNE16,
+  SPARC_BUILTIN_FCMPNE32,
+  SPARC_BUILTIN_FCMPGT16,
+  SPARC_BUILTIN_FCMPGT32,
+  SPARC_BUILTIN_FCMPEQ16,
+  SPARC_BUILTIN_FCMPEQ32,
+  SPARC_BUILTIN_FPADD16,
+  SPARC_BUILTIN_FPADD16S,
+  SPARC_BUILTIN_FPADD32,
+  SPARC_BUILTIN_FPADD32S,
+  SPARC_BUILTIN_FPSUB16,
+  SPARC_BUILTIN_FPSUB16S,
+  SPARC_BUILTIN_FPSUB32,
+  SPARC_BUILTIN_FPSUB32S,
+  SPARC_BUILTIN_ARRAY8,
+  SPARC_BUILTIN_ARRAY16,
+  SPARC_BUILTIN_ARRAY32,
+
+  /* VIS 2.0 builtins.  */
+  SPARC_BUILTIN_EDGE8N,
+  SPARC_BUILTIN_EDGE8LN,
+  SPARC_BUILTIN_EDGE16N,
+  SPARC_BUILTIN_EDGE16LN,
+  SPARC_BUILTIN_EDGE32N,
+  SPARC_BUILTIN_EDGE32LN,
+  SPARC_BUILTIN_BMASK,
+  SPARC_BUILTIN_BSHUFFLEV4HI,
+  SPARC_BUILTIN_BSHUFFLEV8QI,
+  SPARC_BUILTIN_BSHUFFLEV2SI,
+  SPARC_BUILTIN_BSHUFFLEDI,
+
+  /* VIS 3.0 builtins.  */
+  SPARC_BUILTIN_CMASK8,
+  SPARC_BUILTIN_CMASK16,
+  SPARC_BUILTIN_CMASK32,
+  SPARC_BUILTIN_FCHKSM16,
+  SPARC_BUILTIN_FSLL16,
+  SPARC_BUILTIN_FSLAS16,
+  SPARC_BUILTIN_FSRL16,
+  SPARC_BUILTIN_FSRA16,
+  SPARC_BUILTIN_FSLL32,
+  SPARC_BUILTIN_FSLAS32,
+  SPARC_BUILTIN_FSRL32,
+  SPARC_BUILTIN_FSRA32,
+  SPARC_BUILTIN_PDISTN,
+  SPARC_BUILTIN_FMEAN16,
+  SPARC_BUILTIN_FPADD64,
+  SPARC_BUILTIN_FPSUB64,
+  SPARC_BUILTIN_FPADDS16,
+  SPARC_BUILTIN_FPADDS16S,
+  SPARC_BUILTIN_FPSUBS16,
+  SPARC_BUILTIN_FPSUBS16S,
+  SPARC_BUILTIN_FPADDS32,
+  SPARC_BUILTIN_FPADDS32S,
+  SPARC_BUILTIN_FPSUBS32,
+  SPARC_BUILTIN_FPSUBS32S,
+  SPARC_BUILTIN_FUCMPLE8,
+  SPARC_BUILTIN_FUCMPNE8,
+  SPARC_BUILTIN_FUCMPGT8,
+  SPARC_BUILTIN_FUCMPEQ8,
+  SPARC_BUILTIN_FHADDS,
+  SPARC_BUILTIN_FHADDD,
+  SPARC_BUILTIN_FHSUBS,
+  SPARC_BUILTIN_FHSUBD,
+  SPARC_BUILTIN_FNHADDS,
+  SPARC_BUILTIN_FNHADDD,
+  SPARC_BUILTIN_UMULXHI,
+  SPARC_BUILTIN_XMULX,
+  SPARC_BUILTIN_XMULXHI,
+
+  SPARC_BUILTIN_MAX
+};
+
+static GTY (()) tree sparc_builtins[(int) SPARC_BUILTIN_MAX];
+static enum insn_code sparc_builtins_icode[(int) SPARC_BUILTIN_MAX];
+
+/* Add a SPARC builtin function with NAME, ICODE, CODE and TYPE.  Return the
+   function decl or NULL_TREE if the builtin was not added.  */
+
+static tree
+def_builtin (const char *name, enum insn_code icode, enum sparc_builtins code,
+	     tree type)
 {
-  return add_builtin_function(name, type, code, BUILT_IN_MD, NULL,
-			      NULL_TREE);
+  tree t
+    = add_builtin_function (name, type, code, BUILT_IN_MD, NULL, NULL_TREE);
+
+  if (t)
+    {
+      sparc_builtins[code] = t;
+      sparc_builtins_icode[code] = icode;
+    }
+
+  return t;
 }
 
-static tree def_builtin_const(const char *name, int code, tree type)
+/* Likewise, but also marks the function as "const".  */
+
+static tree
+def_builtin_const (const char *name, enum insn_code icode,
+		   enum sparc_builtins code, tree type)
 {
-  tree t = def_builtin(name, code, type);
+  tree t = def_builtin (name, icode, code, type);
 
   if (t)
     TREE_READONLY (t) = 1;
@@ -9991,11 +10127,28 @@ static tree def_builtin_const(const char
 static void
 sparc_init_builtins (void)
 {
+  if (TARGET_FPU)
+    sparc_fpu_init_builtins ();
+
   if (TARGET_VIS)
     sparc_vis_init_builtins ();
 }
 
-/* Create builtin functions for VIS 1.0 instructions.  */
+/* Create builtin functions for FPU instructions.  */
+
+static void
+sparc_fpu_init_builtins (void)
+{
+  tree ftype
+    = build_function_type_list (void_type_node,
+				build_pointer_type (unsigned_type_node), 0);
+  def_builtin ("__builtin_load_fsr", CODE_FOR_ldfsr,
+	       SPARC_BUILTIN_LDFSR, ftype);
+  def_builtin ("__builtin_store_fsr", CODE_FOR_stfsr,
+	       SPARC_BUILTIN_STFSR, ftype);
+}
+
+/* Create builtin functions for VIS instructions.  */
 
 static void
 sparc_vis_init_builtins (void)
@@ -10069,223 +10222,225 @@ sparc_vis_init_builtins (void)
 
   /* Packing and expanding vectors.  */
   def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis,
-	       v4qi_ftype_v4hi);
+	       SPARC_BUILTIN_FPACK16, v4qi_ftype_v4hi);
   def_builtin ("__builtin_vis_fpack32", CODE_FOR_fpack32_vis,
-	       v8qi_ftype_v2si_v8qi);
+	       SPARC_BUILTIN_FPACK32, v8qi_ftype_v2si_v8qi);
   def_builtin ("__builtin_vis_fpackfix", CODE_FOR_fpackfix_vis,
-	       v2hi_ftype_v2si);
+	       SPARC_BUILTIN_FPACKFIX, v2hi_ftype_v2si);
   def_builtin_const ("__builtin_vis_fexpand", CODE_FOR_fexpand_vis,
-		     v4hi_ftype_v4qi);
+		     SPARC_BUILTIN_FEXPAND, v4hi_ftype_v4qi);
   def_builtin_const ("__builtin_vis_fpmerge", CODE_FOR_fpmerge_vis,
-		     v8qi_ftype_v4qi_v4qi);
+		     SPARC_BUILTIN_FPMERGE, v8qi_ftype_v4qi_v4qi);
 
   /* Multiplications.  */
   def_builtin_const ("__builtin_vis_fmul8x16", CODE_FOR_fmul8x16_vis,
-		     v4hi_ftype_v4qi_v4hi);
+		     SPARC_BUILTIN_FMUL8X16, v4hi_ftype_v4qi_v4hi);
   def_builtin_const ("__builtin_vis_fmul8x16au", CODE_FOR_fmul8x16au_vis,
-		     v4hi_ftype_v4qi_v2hi);
+		     SPARC_BUILTIN_FMUL8X16AU, v4hi_ftype_v4qi_v2hi);
   def_builtin_const ("__builtin_vis_fmul8x16al", CODE_FOR_fmul8x16al_vis,
-		     v4hi_ftype_v4qi_v2hi);
+		     SPARC_BUILTIN_FMUL8X16AL, v4hi_ftype_v4qi_v2hi);
   def_builtin_const ("__builtin_vis_fmul8sux16", CODE_FOR_fmul8sux16_vis,
-		     v4hi_ftype_v8qi_v4hi);
+		     SPARC_BUILTIN_FMUL8SUX16, v4hi_ftype_v8qi_v4hi);
   def_builtin_const ("__builtin_vis_fmul8ulx16", CODE_FOR_fmul8ulx16_vis,
-		     v4hi_ftype_v8qi_v4hi);
+		     SPARC_BUILTIN_FMUL8ULX16, v4hi_ftype_v8qi_v4hi);
   def_builtin_const ("__builtin_vis_fmuld8sux16", CODE_FOR_fmuld8sux16_vis,
-		     v2si_ftype_v4qi_v2hi);
+		     SPARC_BUILTIN_FMULD8SUX16, v2si_ftype_v4qi_v2hi);
   def_builtin_const ("__builtin_vis_fmuld8ulx16", CODE_FOR_fmuld8ulx16_vis,
-		     v2si_ftype_v4qi_v2hi);
+		     SPARC_BUILTIN_FMULD8ULX16, v2si_ftype_v4qi_v2hi);
 
   /* Data aligning.  */
   def_builtin ("__builtin_vis_faligndatav4hi", CODE_FOR_faligndatav4hi_vis,
-	       v4hi_ftype_v4hi_v4hi);
+	       SPARC_BUILTIN_FALIGNDATAV4HI, v4hi_ftype_v4hi_v4hi);
   def_builtin ("__builtin_vis_faligndatav8qi", CODE_FOR_faligndatav8qi_vis,
-	       v8qi_ftype_v8qi_v8qi);
+	       SPARC_BUILTIN_FALIGNDATAV8QI, v8qi_ftype_v8qi_v8qi);
   def_builtin ("__builtin_vis_faligndatav2si", CODE_FOR_faligndatav2si_vis,
-	       v2si_ftype_v2si_v2si);
+	       SPARC_BUILTIN_FALIGNDATAV2SI, v2si_ftype_v2si_v2si);
   def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatav1di_vis,
-	       di_ftype_di_di);
+	       SPARC_BUILTIN_FALIGNDATADI, di_ftype_di_di);
 
   def_builtin ("__builtin_vis_write_gsr", CODE_FOR_wrgsr_vis,
-	       void_ftype_di);
+	       SPARC_BUILTIN_WRGSR, void_ftype_di);
   def_builtin ("__builtin_vis_read_gsr", CODE_FOR_rdgsr_vis,
-	       di_ftype_void);
+	       SPARC_BUILTIN_RDGSR, di_ftype_void);
 
   if (TARGET_ARCH64)
     {
       def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis,
-		   ptr_ftype_ptr_di);
+		   SPARC_BUILTIN_ALIGNADDR, ptr_ftype_ptr_di);
       def_builtin ("__builtin_vis_alignaddrl", CODE_FOR_alignaddrldi_vis,
-		   ptr_ftype_ptr_di);
+		   SPARC_BUILTIN_ALIGNADDRL, ptr_ftype_ptr_di);
     }
   else
     {
       def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrsi_vis,
-		   ptr_ftype_ptr_si);
+		   SPARC_BUILTIN_ALIGNADDR, ptr_ftype_ptr_si);
       def_builtin ("__builtin_vis_alignaddrl", CODE_FOR_alignaddrlsi_vis,
-		   ptr_ftype_ptr_si);
+		   SPARC_BUILTIN_ALIGNADDRL, ptr_ftype_ptr_si);
     }
 
   /* Pixel distance.  */
   def_builtin_const ("__builtin_vis_pdist", CODE_FOR_pdist_vis,
-		     di_ftype_v8qi_v8qi_di);
+		     SPARC_BUILTIN_PDIST, di_ftype_v8qi_v8qi_di);
 
   /* Edge handling.  */
   if (TARGET_ARCH64)
     {
       def_builtin_const ("__builtin_vis_edge8", CODE_FOR_edge8di_vis,
-			 di_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE8, di_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge8l", CODE_FOR_edge8ldi_vis,
-			 di_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE8L, di_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge16", CODE_FOR_edge16di_vis,
-			 di_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE16, di_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge16l", CODE_FOR_edge16ldi_vis,
-			 di_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE16L, di_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge32", CODE_FOR_edge32di_vis,
-			 di_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE32, di_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge32l", CODE_FOR_edge32ldi_vis,
-			 di_ftype_ptr_ptr);
-      if (TARGET_VIS2)
-	{
-	  def_builtin_const ("__builtin_vis_edge8n", CODE_FOR_edge8ndi_vis,
-			     di_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge8ln", CODE_FOR_edge8lndi_vis,
-			     di_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge16n", CODE_FOR_edge16ndi_vis,
-			     di_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge16ln", CODE_FOR_edge16lndi_vis,
-			     di_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge32n", CODE_FOR_edge32ndi_vis,
-			     di_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge32ln", CODE_FOR_edge32lndi_vis,
-			     di_ftype_ptr_ptr);
-	}
+			 SPARC_BUILTIN_EDGE32L, di_ftype_ptr_ptr);
     }
   else
     {
       def_builtin_const ("__builtin_vis_edge8", CODE_FOR_edge8si_vis,
-			 si_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE8, si_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge8l", CODE_FOR_edge8lsi_vis,
-			 si_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE8L, si_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge16", CODE_FOR_edge16si_vis,
-			 si_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE16, si_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge16l", CODE_FOR_edge16lsi_vis,
-			 si_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE16L, si_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge32", CODE_FOR_edge32si_vis,
-			 si_ftype_ptr_ptr);
+			 SPARC_BUILTIN_EDGE32, si_ftype_ptr_ptr);
       def_builtin_const ("__builtin_vis_edge32l", CODE_FOR_edge32lsi_vis,
-			 si_ftype_ptr_ptr);
-      if (TARGET_VIS2)
-	{
-	  def_builtin_const ("__builtin_vis_edge8n", CODE_FOR_edge8nsi_vis,
-			     si_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge8ln", CODE_FOR_edge8lnsi_vis,
-			     si_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge16n", CODE_FOR_edge16nsi_vis,
-			     si_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge16ln", CODE_FOR_edge16lnsi_vis,
-			     si_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge32n", CODE_FOR_edge32nsi_vis,
-			     si_ftype_ptr_ptr);
-	  def_builtin_const ("__builtin_vis_edge32ln", CODE_FOR_edge32lnsi_vis,
-			     si_ftype_ptr_ptr);
-	}
+			 SPARC_BUILTIN_EDGE32L, si_ftype_ptr_ptr);
     }
 
   /* Pixel compare.  */
   if (TARGET_ARCH64)
     {
       def_builtin_const ("__builtin_vis_fcmple16", CODE_FOR_fcmple16di_vis,
-			 di_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPLE16, di_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmple32", CODE_FOR_fcmple32di_vis,
-			 di_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPLE32, di_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fcmpne16", CODE_FOR_fcmpne16di_vis,
-			 di_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPNE16, di_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmpne32", CODE_FOR_fcmpne32di_vis,
-			 di_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPNE32, di_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fcmpgt16", CODE_FOR_fcmpgt16di_vis,
-			 di_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPGT16, di_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmpgt32", CODE_FOR_fcmpgt32di_vis,
-			 di_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPGT32, di_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fcmpeq16", CODE_FOR_fcmpeq16di_vis,
-			 di_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPEQ16, di_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmpeq32", CODE_FOR_fcmpeq32di_vis,
-			 di_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPEQ32, di_ftype_v2si_v2si);
     }
   else
     {
       def_builtin_const ("__builtin_vis_fcmple16", CODE_FOR_fcmple16si_vis,
-			 si_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPLE16, si_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmple32", CODE_FOR_fcmple32si_vis,
-			 si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPLE32, si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fcmpne16", CODE_FOR_fcmpne16si_vis,
-			 si_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPNE16, si_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmpne32", CODE_FOR_fcmpne32si_vis,
-			 si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPNE32, si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fcmpgt16", CODE_FOR_fcmpgt16si_vis,
-			 si_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPGT16, si_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmpgt32", CODE_FOR_fcmpgt32si_vis,
-			 si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPGT32, si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fcmpeq16", CODE_FOR_fcmpeq16si_vis,
-			 si_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCMPEQ16, si_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fcmpeq32", CODE_FOR_fcmpeq32si_vis,
-			 si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FCMPEQ32, si_ftype_v2si_v2si);
     }
 
   /* Addition and subtraction.  */
   def_builtin_const ("__builtin_vis_fpadd16", CODE_FOR_addv4hi3,
-		     v4hi_ftype_v4hi_v4hi);
+		     SPARC_BUILTIN_FPADD16, v4hi_ftype_v4hi_v4hi);
   def_builtin_const ("__builtin_vis_fpadd16s", CODE_FOR_addv2hi3,
-		     v2hi_ftype_v2hi_v2hi);
+		     SPARC_BUILTIN_FPADD16S, v2hi_ftype_v2hi_v2hi);
   def_builtin_const ("__builtin_vis_fpadd32", CODE_FOR_addv2si3,
-		     v2si_ftype_v2si_v2si);
+		     SPARC_BUILTIN_FPADD32, v2si_ftype_v2si_v2si);
   def_builtin_const ("__builtin_vis_fpadd32s", CODE_FOR_addv1si3,
-		     v1si_ftype_v1si_v1si);
+		     SPARC_BUILTIN_FPADD32S, v1si_ftype_v1si_v1si);
   def_builtin_const ("__builtin_vis_fpsub16", CODE_FOR_subv4hi3,
-		     v4hi_ftype_v4hi_v4hi);
+		     SPARC_BUILTIN_FPSUB16, v4hi_ftype_v4hi_v4hi);
   def_builtin_const ("__builtin_vis_fpsub16s", CODE_FOR_subv2hi3,
-		     v2hi_ftype_v2hi_v2hi);
+		     SPARC_BUILTIN_FPSUB16S, v2hi_ftype_v2hi_v2hi);
   def_builtin_const ("__builtin_vis_fpsub32", CODE_FOR_subv2si3,
-		     v2si_ftype_v2si_v2si);
+		     SPARC_BUILTIN_FPSUB32, v2si_ftype_v2si_v2si);
   def_builtin_const ("__builtin_vis_fpsub32s", CODE_FOR_subv1si3,
-		     v1si_ftype_v1si_v1si);
+		     SPARC_BUILTIN_FPSUB32S, v1si_ftype_v1si_v1si);
 
   /* Three-dimensional array addressing.  */
   if (TARGET_ARCH64)
     {
       def_builtin_const ("__builtin_vis_array8", CODE_FOR_array8di_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_ARRAY8, di_ftype_di_di);
       def_builtin_const ("__builtin_vis_array16", CODE_FOR_array16di_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_ARRAY16, di_ftype_di_di);
       def_builtin_const ("__builtin_vis_array32", CODE_FOR_array32di_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_ARRAY32, di_ftype_di_di);
     }
   else
     {
       def_builtin_const ("__builtin_vis_array8", CODE_FOR_array8si_vis,
-			 si_ftype_si_si);
+			 SPARC_BUILTIN_ARRAY8, si_ftype_si_si);
       def_builtin_const ("__builtin_vis_array16", CODE_FOR_array16si_vis,
-			 si_ftype_si_si);
+			 SPARC_BUILTIN_ARRAY16, si_ftype_si_si);
       def_builtin_const ("__builtin_vis_array32", CODE_FOR_array32si_vis,
-			 si_ftype_si_si);
-  }
+			 SPARC_BUILTIN_ARRAY32, si_ftype_si_si);
+    }
 
   if (TARGET_VIS2)
     {
-      /* Byte mask and shuffle */
+      /* Edge handling.  */
+      if (TARGET_ARCH64)
+	{
+	  def_builtin_const ("__builtin_vis_edge8n", CODE_FOR_edge8ndi_vis,
+			     SPARC_BUILTIN_EDGE8N, di_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge8ln", CODE_FOR_edge8lndi_vis,
+			     SPARC_BUILTIN_EDGE8LN, di_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge16n", CODE_FOR_edge16ndi_vis,
+			     SPARC_BUILTIN_EDGE16N, di_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge16ln", CODE_FOR_edge16lndi_vis,
+			     SPARC_BUILTIN_EDGE16LN, di_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge32n", CODE_FOR_edge32ndi_vis,
+			     SPARC_BUILTIN_EDGE32N, di_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge32ln", CODE_FOR_edge32lndi_vis,
+			     SPARC_BUILTIN_EDGE32LN, di_ftype_ptr_ptr);
+	}
+      else
+	{
+	  def_builtin_const ("__builtin_vis_edge8n", CODE_FOR_edge8nsi_vis,
+			     SPARC_BUILTIN_EDGE8N, si_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge8ln", CODE_FOR_edge8lnsi_vis,
+			     SPARC_BUILTIN_EDGE8LN, si_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge16n", CODE_FOR_edge16nsi_vis,
+			     SPARC_BUILTIN_EDGE16N, si_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge16ln", CODE_FOR_edge16lnsi_vis,
+			     SPARC_BUILTIN_EDGE16LN, si_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge32n", CODE_FOR_edge32nsi_vis,
+			     SPARC_BUILTIN_EDGE32N, si_ftype_ptr_ptr);
+	  def_builtin_const ("__builtin_vis_edge32ln", CODE_FOR_edge32lnsi_vis,
+			     SPARC_BUILTIN_EDGE32LN, si_ftype_ptr_ptr);
+	}
+
+      /* Byte mask and shuffle.  */
       if (TARGET_ARCH64)
 	def_builtin ("__builtin_vis_bmask", CODE_FOR_bmaskdi_vis,
-		     di_ftype_di_di);
+		     SPARC_BUILTIN_BMASK, di_ftype_di_di);
       else
 	def_builtin ("__builtin_vis_bmask", CODE_FOR_bmasksi_vis,
-		     si_ftype_si_si);
+		     SPARC_BUILTIN_BMASK, si_ftype_si_si);
       def_builtin ("__builtin_vis_bshufflev4hi", CODE_FOR_bshufflev4hi_vis,
-		   v4hi_ftype_v4hi_v4hi);
+		   SPARC_BUILTIN_BSHUFFLEV4HI, v4hi_ftype_v4hi_v4hi);
       def_builtin ("__builtin_vis_bshufflev8qi", CODE_FOR_bshufflev8qi_vis,
-		   v8qi_ftype_v8qi_v8qi);
+		   SPARC_BUILTIN_BSHUFFLEV8QI, v8qi_ftype_v8qi_v8qi);
       def_builtin ("__builtin_vis_bshufflev2si", CODE_FOR_bshufflev2si_vis,
-		   v2si_ftype_v2si_v2si);
+		   SPARC_BUILTIN_BSHUFFLEV2SI, v2si_ftype_v2si_v2si);
       def_builtin ("__builtin_vis_bshuffledi", CODE_FOR_bshufflev1di_vis,
-		   di_ftype_di_di);
+		   SPARC_BUILTIN_BSHUFFLEDI, di_ftype_di_di);
     }
 
   if (TARGET_VIS3)
@@ -10293,120 +10448,130 @@ sparc_vis_init_builtins (void)
       if (TARGET_ARCH64)
 	{
 	  def_builtin ("__builtin_vis_cmask8", CODE_FOR_cmask8di_vis,
-		       void_ftype_di);
+		       SPARC_BUILTIN_CMASK8, void_ftype_di);
 	  def_builtin ("__builtin_vis_cmask16", CODE_FOR_cmask16di_vis,
-		       void_ftype_di);
+		       SPARC_BUILTIN_CMASK16, void_ftype_di);
 	  def_builtin ("__builtin_vis_cmask32", CODE_FOR_cmask32di_vis,
-		       void_ftype_di);
+		       SPARC_BUILTIN_CMASK32, void_ftype_di);
 	}
       else
 	{
 	  def_builtin ("__builtin_vis_cmask8", CODE_FOR_cmask8si_vis,
-		       void_ftype_si);
+		       SPARC_BUILTIN_CMASK8, void_ftype_si);
 	  def_builtin ("__builtin_vis_cmask16", CODE_FOR_cmask16si_vis,
-		       void_ftype_si);
+		       SPARC_BUILTIN_CMASK16, void_ftype_si);
 	  def_builtin ("__builtin_vis_cmask32", CODE_FOR_cmask32si_vis,
-		       void_ftype_si);
+		       SPARC_BUILTIN_CMASK32, void_ftype_si);
 	}
 
       def_builtin_const ("__builtin_vis_fchksm16", CODE_FOR_fchksm16_vis,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FCHKSM16, v4hi_ftype_v4hi_v4hi);
 
       def_builtin_const ("__builtin_vis_fsll16", CODE_FOR_vashlv4hi3,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FSLL16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fslas16", CODE_FOR_vssashlv4hi3,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FSLAS16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fsrl16", CODE_FOR_vlshrv4hi3,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FSRL16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fsra16", CODE_FOR_vashrv4hi3,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FSRA16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fsll32", CODE_FOR_vashlv2si3,
-			 v2si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FSLL32, v2si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fslas32", CODE_FOR_vssashlv2si3,
-			 v2si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FSLAS32, v2si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fsrl32", CODE_FOR_vlshrv2si3,
-			 v2si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FSRL32, v2si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fsra32", CODE_FOR_vashrv2si3,
-			 v2si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FSRA32, v2si_ftype_v2si_v2si);
 
       if (TARGET_ARCH64)
 	def_builtin_const ("__builtin_vis_pdistn", CODE_FOR_pdistndi_vis,
-			   di_ftype_v8qi_v8qi);
+			   SPARC_BUILTIN_PDISTN, di_ftype_v8qi_v8qi);
       else
 	def_builtin_const ("__builtin_vis_pdistn", CODE_FOR_pdistnsi_vis,
-			   si_ftype_v8qi_v8qi);
+			   SPARC_BUILTIN_PDISTN, si_ftype_v8qi_v8qi);
 
       def_builtin_const ("__builtin_vis_fmean16", CODE_FOR_fmean16_vis,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FMEAN16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fpadd64", CODE_FOR_fpadd64_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_FPADD64, di_ftype_di_di);
       def_builtin_const ("__builtin_vis_fpsub64", CODE_FOR_fpsub64_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_FPSUB64, di_ftype_di_di);
 
       def_builtin_const ("__builtin_vis_fpadds16", CODE_FOR_ssaddv4hi3,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FPADDS16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fpadds16s", CODE_FOR_ssaddv2hi3,
-			 v2hi_ftype_v2hi_v2hi);
+			 SPARC_BUILTIN_FPADDS16S, v2hi_ftype_v2hi_v2hi);
       def_builtin_const ("__builtin_vis_fpsubs16", CODE_FOR_sssubv4hi3,
-			 v4hi_ftype_v4hi_v4hi);
+			 SPARC_BUILTIN_FPSUBS16, v4hi_ftype_v4hi_v4hi);
       def_builtin_const ("__builtin_vis_fpsubs16s", CODE_FOR_sssubv2hi3,
-			 v2hi_ftype_v2hi_v2hi);
+			 SPARC_BUILTIN_FPSUBS16S, v2hi_ftype_v2hi_v2hi);
       def_builtin_const ("__builtin_vis_fpadds32", CODE_FOR_ssaddv2si3,
-			 v2si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FPADDS32, v2si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fpadds32s", CODE_FOR_ssaddv1si3,
-			 v1si_ftype_v1si_v1si);
+			 SPARC_BUILTIN_FPADDS32S, v1si_ftype_v1si_v1si);
       def_builtin_const ("__builtin_vis_fpsubs32", CODE_FOR_sssubv2si3,
-			 v2si_ftype_v2si_v2si);
+			 SPARC_BUILTIN_FPSUBS32, v2si_ftype_v2si_v2si);
       def_builtin_const ("__builtin_vis_fpsubs32s", CODE_FOR_sssubv1si3,
-			 v1si_ftype_v1si_v1si);
+			 SPARC_BUILTIN_FPSUBS32S, v1si_ftype_v1si_v1si);
 
       if (TARGET_ARCH64)
 	{
 	  def_builtin_const ("__builtin_vis_fucmple8", CODE_FOR_fucmple8di_vis,
-			     di_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPLE8, di_ftype_v8qi_v8qi);
 	  def_builtin_const ("__builtin_vis_fucmpne8", CODE_FOR_fucmpne8di_vis,
-			     di_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPNE8, di_ftype_v8qi_v8qi);
 	  def_builtin_const ("__builtin_vis_fucmpgt8", CODE_FOR_fucmpgt8di_vis,
-			     di_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPGT8, di_ftype_v8qi_v8qi);
 	  def_builtin_const ("__builtin_vis_fucmpeq8", CODE_FOR_fucmpeq8di_vis,
-			     di_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPEQ8, di_ftype_v8qi_v8qi);
 	}
       else
 	{
 	  def_builtin_const ("__builtin_vis_fucmple8", CODE_FOR_fucmple8si_vis,
-			     si_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPLE8, si_ftype_v8qi_v8qi);
 	  def_builtin_const ("__builtin_vis_fucmpne8", CODE_FOR_fucmpne8si_vis,
-			     si_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPNE8, si_ftype_v8qi_v8qi);
 	  def_builtin_const ("__builtin_vis_fucmpgt8", CODE_FOR_fucmpgt8si_vis,
-			     si_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPGT8, si_ftype_v8qi_v8qi);
 	  def_builtin_const ("__builtin_vis_fucmpeq8", CODE_FOR_fucmpeq8si_vis,
-			     si_ftype_v8qi_v8qi);
+			     SPARC_BUILTIN_FUCMPEQ8, si_ftype_v8qi_v8qi);
 	}
 
       def_builtin_const ("__builtin_vis_fhadds", CODE_FOR_fhaddsf_vis,
-			 sf_ftype_sf_sf);
+			 SPARC_BUILTIN_FHADDS, sf_ftype_sf_sf);
       def_builtin_const ("__builtin_vis_fhaddd", CODE_FOR_fhadddf_vis,
-			 df_ftype_df_df);
+			 SPARC_BUILTIN_FHADDD, df_ftype_df_df);
       def_builtin_const ("__builtin_vis_fhsubs", CODE_FOR_fhsubsf_vis,
-			 sf_ftype_sf_sf);
+			 SPARC_BUILTIN_FHSUBS, sf_ftype_sf_sf);
       def_builtin_const ("__builtin_vis_fhsubd", CODE_FOR_fhsubdf_vis,
-			 df_ftype_df_df);
+			 SPARC_BUILTIN_FHSUBD, df_ftype_df_df);
       def_builtin_const ("__builtin_vis_fnhadds", CODE_FOR_fnhaddsf_vis,
-			 sf_ftype_sf_sf);
+			 SPARC_BUILTIN_FNHADDS, sf_ftype_sf_sf);
       def_builtin_const ("__builtin_vis_fnhaddd", CODE_FOR_fnhadddf_vis,
-			 df_ftype_df_df);
+			 SPARC_BUILTIN_FNHADDD, df_ftype_df_df);
 
       def_builtin_const ("__builtin_vis_umulxhi", CODE_FOR_umulxhi_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_UMULXHI, di_ftype_di_di);
       def_builtin_const ("__builtin_vis_xmulx", CODE_FOR_xmulx_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_XMULX, di_ftype_di_di);
       def_builtin_const ("__builtin_vis_xmulxhi", CODE_FOR_xmulxhi_vis,
-			 di_ftype_di_di);
+			 SPARC_BUILTIN_XMULXHI, di_ftype_di_di);
     }
 }
 
-/* Handle TARGET_EXPAND_BUILTIN target hook.
-   Expand builtin functions for sparc intrinsics.  */
+/* Implement TARGET_BUILTIN_DECL hook.  */
+
+static tree
+sparc_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  if (code >= SPARC_BUILTIN_MAX)
+    return error_mark_node;
+
+  return sparc_builtins[code];
+}
+
+/* Implemented TARGET_EXPAND_BUILTIN hook.  */
 
 static rtx
 sparc_expand_builtin (tree exp, rtx target,
@@ -10414,15 +10579,14 @@ sparc_expand_builtin (tree exp, rtx targ
 		      enum machine_mode tmode ATTRIBUTE_UNUSED,
 		      int ignore ATTRIBUTE_UNUSED)
 {
-  tree arg;
-  call_expr_arg_iterator iter;
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  unsigned int icode = DECL_FUNCTION_CODE (fndecl);
-  rtx pat, op[4];
+  enum sparc_builtins code = (enum sparc_builtins) DECL_FUNCTION_CODE (fndecl);
+  enum insn_code icode = sparc_builtins_icode[code];
+  bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+  call_expr_arg_iterator iter;
   int arg_count = 0;
-  bool nonvoid;
-
-  nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+  rtx pat, op[4];
+  tree arg;
 
   if (nonvoid)
     {
@@ -10434,6 +10598,7 @@ sparc_expand_builtin (tree exp, rtx targ
       else
 	op[0] = target;
     }
+
   FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
     {
       const struct insn_operand_data *insn_op;
@@ -10447,11 +10612,22 @@ sparc_expand_builtin (tree exp, rtx targ
       insn_op = &insn_data[icode].operand[idx];
       op[arg_count] = expand_normal (arg);
 
-      if (insn_op->mode == V1DImode
-	  && GET_MODE (op[arg_count]) == DImode)
+      if (code == SPARC_BUILTIN_LDFSR || code == SPARC_BUILTIN_STFSR)
+	{
+	  if (!address_operand (op[arg_count], SImode))
+	    {
+	      op[arg_count] = convert_memory_address (Pmode, op[arg_count]);
+	      op[arg_count] = copy_addr_to_reg (op[arg_count]);
+	    }
+	  op[arg_count] = gen_rtx_MEM (SImode, op[arg_count]);
+	}
+
+      else if (insn_op->mode == V1DImode
+	       && GET_MODE (op[arg_count]) == DImode)
 	op[arg_count] = gen_lowpart (V1DImode, op[arg_count]);
+
       else if (insn_op->mode == V1SImode
-	  && GET_MODE (op[arg_count]) == SImode)
+	       && GET_MODE (op[arg_count]) == SImode)
 	op[arg_count] = gen_lowpart (V1SImode, op[arg_count]);
 
       if (! (*insn_data[icode].operand[idx].predicate) (op[arg_count],
@@ -10485,12 +10661,11 @@ sparc_expand_builtin (tree exp, rtx targ
 
   emit_insn (pat);
 
-  if (nonvoid)
-    return op[0];
-  else
-    return const0_rtx;
+  return (nonvoid ? op[0] : const0_rtx);
 }
 
+/* Return the upper 16 bits of the 8x16 multiplication.  */
+
 static int
 sparc_vis_mul8x16 (int e8, int e16)
 {
@@ -10501,15 +10676,15 @@ sparc_vis_mul8x16 (int e8, int e16)
    the result into the array N_ELTS, whose elements are of INNER_TYPE.  */
 
 static void
-sparc_handle_vis_mul8x16 (tree *n_elts, int fncode, tree inner_type,
-			  tree cst0, tree cst1)
+sparc_handle_vis_mul8x16 (tree *n_elts, enum sparc_builtins fncode,
+			  tree inner_type, tree cst0, tree cst1)
 {
   unsigned i, num = VECTOR_CST_NELTS (cst0);
   int scale;
 
   switch (fncode)
     {
-    case CODE_FOR_fmul8x16_vis:
+    case SPARC_BUILTIN_FMUL8X16:
       for (i = 0; i < num; ++i)
 	{
 	  int val
@@ -10519,7 +10694,7 @@ sparc_handle_vis_mul8x16 (tree *n_elts,
 	}
       break;
 
-    case CODE_FOR_fmul8x16au_vis:
+    case SPARC_BUILTIN_FMUL8X16AU:
       scale = TREE_INT_CST_LOW (VECTOR_CST_ELT (cst1, 0));
 
       for (i = 0; i < num; ++i)
@@ -10531,7 +10706,7 @@ sparc_handle_vis_mul8x16 (tree *n_elts,
 	}
       break;
 
-    case CODE_FOR_fmul8x16al_vis:
+    case SPARC_BUILTIN_FMUL8X16AL:
       scale = TREE_INT_CST_LOW (VECTOR_CST_ELT (cst1, 1));
 
       for (i = 0; i < num; ++i)
@@ -10548,7 +10723,8 @@ sparc_handle_vis_mul8x16 (tree *n_elts,
     }
 }
 
-/* Handle TARGET_FOLD_BUILTIN target hook.
+/* Implement TARGET_FOLD_BUILTIN hook.
+
    Fold builtin functions for SPARC intrinsics.  If IGNORE is true the
    result of the function call is ignored.  NULL_TREE is returned if the
    function could not be folded.  */
@@ -10557,34 +10733,30 @@ static tree
 sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
 		    tree *args, bool ignore)
 {
-  tree arg0, arg1, arg2;
+  enum sparc_builtins code = (enum sparc_builtins) DECL_FUNCTION_CODE (fndecl);
   tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
-  enum insn_code icode = (enum insn_code) DECL_FUNCTION_CODE (fndecl);
+  tree arg0, arg1, arg2;
 
   if (ignore)
-    {
-      /* Note that a switch statement instead of the sequence of tests would
-	 be incorrect as many of the CODE_FOR values could be CODE_FOR_nothing
-	 and that would yield multiple alternatives with identical values.  */
-      if (icode == CODE_FOR_alignaddrsi_vis
-	  || icode == CODE_FOR_alignaddrdi_vis
-	  || icode == CODE_FOR_wrgsr_vis
-	  || icode == CODE_FOR_bmasksi_vis
-	  || icode == CODE_FOR_bmaskdi_vis
-	  || icode == CODE_FOR_cmask8si_vis
-	  || icode == CODE_FOR_cmask8di_vis
-	  || icode == CODE_FOR_cmask16si_vis
-	  || icode == CODE_FOR_cmask16di_vis
-	  || icode == CODE_FOR_cmask32si_vis
-	  || icode == CODE_FOR_cmask32di_vis)
-	;
-      else
+    switch (code)
+      {
+      case SPARC_BUILTIN_LDFSR:
+      case SPARC_BUILTIN_STFSR:
+      case SPARC_BUILTIN_ALIGNADDR:
+      case SPARC_BUILTIN_WRGSR:
+      case SPARC_BUILTIN_BMASK:
+      case SPARC_BUILTIN_CMASK8:
+      case SPARC_BUILTIN_CMASK16:
+      case SPARC_BUILTIN_CMASK32:
+	break;
+
+      default:
 	return build_zero_cst (rtype);
-    }
+      }
 
-  switch (icode)
+  switch (code)
     {
-    case CODE_FOR_fexpand_vis:
+    case SPARC_BUILTIN_FEXPAND:
       arg0 = args[0];
       STRIP_NOPS (arg0);
 
@@ -10603,9 +10775,9 @@ sparc_fold_builtin (tree fndecl, int n_a
 	}
       break;
 
-    case CODE_FOR_fmul8x16_vis:
-    case CODE_FOR_fmul8x16au_vis:
-    case CODE_FOR_fmul8x16al_vis:
+    case SPARC_BUILTIN_FMUL8X16:
+    case SPARC_BUILTIN_FMUL8X16AU:
+    case SPARC_BUILTIN_FMUL8X16AL:
       arg0 = args[0];
       arg1 = args[1];
       STRIP_NOPS (arg0);
@@ -10615,12 +10787,12 @@ sparc_fold_builtin (tree fndecl, int n_a
 	{
 	  tree inner_type = TREE_TYPE (rtype);
 	  tree *n_elts = XALLOCAVEC (tree, VECTOR_CST_NELTS (arg0));
-	  sparc_handle_vis_mul8x16 (n_elts, icode, inner_type, arg0, arg1);
+	  sparc_handle_vis_mul8x16 (n_elts, code, inner_type, arg0, arg1);
 	  return build_vector (rtype, n_elts);
 	}
       break;
 
-    case CODE_FOR_fpmerge_vis:
+    case SPARC_BUILTIN_FPMERGE:
       arg0 = args[0];
       arg1 = args[1];
       STRIP_NOPS (arg0);
@@ -10640,13 +10812,19 @@ sparc_fold_builtin (tree fndecl, int n_a
 	}
       break;
 
-    case CODE_FOR_pdist_vis:
+    case SPARC_BUILTIN_PDIST:
+    case SPARC_BUILTIN_PDISTN:
       arg0 = args[0];
       arg1 = args[1];
-      arg2 = args[2];
       STRIP_NOPS (arg0);
       STRIP_NOPS (arg1);
-      STRIP_NOPS (arg2);
+      if (code == SPARC_BUILTIN_PDIST)
+	{
+	  arg2 = args[2];
+	  STRIP_NOPS (arg2);
+	}
+      else
+	arg2 = integer_zero_node;
 
       if (TREE_CODE (arg0) == VECTOR_CST
 	  && TREE_CODE (arg1) == VECTOR_CST
@@ -12325,9 +12503,134 @@ sparc_modes_tieable_p (enum machine_mode
   return true;
 }
 
-static enum machine_mode sparc_cstore_mode (enum insn_code icode ATTRIBUTE_UNUSED)
+/* Implement TARGET_CSTORE_MODE.  */
+
+static enum machine_mode
+sparc_cstore_mode (enum insn_code icode ATTRIBUTE_UNUSED)
 {
   return (TARGET_ARCH64 ? DImode : SImode);
 }
 
+/* Return the compound expression made of T1 and T2.  */
+
+static inline tree
+compound_expr (tree t1, tree t2)
+{
+  return build2 (COMPOUND_EXPR, void_type_node, t1, t2);
+}
+
+/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV hook.  */
+
+static void
+sparc_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
+{
+  if (!TARGET_FPU)
+    return;
+
+  const unsigned HOST_WIDE_INT accrued_exception_mask = 0x1f << 5;
+  const unsigned HOST_WIDE_INT trap_enable_mask = 0x1f << 23;
+
+  /* We generate the equivalent of feholdexcept (&fenv_var):
+
+       unsigned int fenv_var;
+       __builtin_store_fsr (&fenv_var);
+
+       unsigned int tmp1_var;
+       tmp1_var = fenv_var & ~(accrued_exception_mask | trap_enable_mask);
+
+       __builtin_load_fsr (&tmp1_var);  */
+
+  tree fenv_var = create_tmp_var (unsigned_type_node, NULL);
+  mark_addressable (fenv_var);
+  tree fenv_addr = build_fold_addr_expr (fenv_var);
+  tree stfsr = sparc_builtins[SPARC_BUILTIN_STFSR];
+  tree hold_stfsr = build_call_expr (stfsr, 1, fenv_addr);
+
+  tree tmp1_var = create_tmp_var (unsigned_type_node, NULL);
+  mark_addressable (tmp1_var);
+  tree masked_fenv_var
+    = build2 (BIT_AND_EXPR, unsigned_type_node, fenv_var,
+	      build_int_cst (unsigned_type_node,
+			     ~(accrued_exception_mask | trap_enable_mask)));
+  tree hold_mask
+    = build2 (MODIFY_EXPR, void_type_node, tmp1_var, masked_fenv_var);
+
+  tree tmp1_addr = build_fold_addr_expr (tmp1_var);
+  tree ldfsr = sparc_builtins[SPARC_BUILTIN_LDFSR];
+  tree hold_ldfsr = build_call_expr (ldfsr, 1, tmp1_addr);
+
+  *hold = compound_expr (compound_expr (hold_stfsr, hold_mask), hold_ldfsr);
+
+  /* We generate the equivalent of feclearexcept (FE_ALL_EXCEPT):
+
+       unsigned int tmp2_var;
+       __builtin_store_fsr (&tmp2_var);
+
+       tmp2_var &= ~accrued_exception_mask;
+
+       __builtin_load_fsr (&tmp2_var);  */
+
+  tree tmp2_var = create_tmp_var (unsigned_type_node, NULL);
+  mark_addressable (tmp2_var);
+  tree tmp2_addr = build_fold_addr_expr (tmp2_var);
+  tree clear_stfsr = build_call_expr (stfsr, 1, tmp2_addr);
+
+  tree masked_tmp2_var
+    = build2 (BIT_AND_EXPR, unsigned_type_node, tmp2_var,
+	      build_int_cst (unsigned_type_node, ~accrued_exception_mask));
+  tree clear_mask
+    = build2 (MODIFY_EXPR, void_type_node, tmp2_var, masked_tmp2_var);
+
+  tree clear_ldfsr = build_call_expr (ldfsr, 1, tmp2_addr);
+
+  *clear
+    = compound_expr (compound_expr (clear_stfsr, clear_mask), clear_ldfsr);
+
+  /* We generate the equivalent of feupdateenv (&fenv_var):
+
+       unsigned int tmp3_var;
+       __builtin_store_fsr (&tmp3_var);
+
+       __builtin_load_fsr (&fenv_var);
+
+       tmp3_var &= accrued_exception_mask;
+       if (SPARC_LOW_FE_EXCEPT_VALUES)
+         tmp3_var >>= 5;
+
+       __atomic_feraiseexcept ((int) tmp3_var);  */
+
+  tree tmp3_var = create_tmp_var (unsigned_type_node, NULL);
+  mark_addressable (tmp3_var);
+  tree tmp3_addr = build_fold_addr_expr (tmp3_var);
+  tree update_stfsr = build_call_expr (stfsr, 1, tmp3_addr);
+
+  tree update_ldfsr = build_call_expr (ldfsr, 1, fenv_addr);
+
+  tree masked_tmp3_var
+    = build2 (BIT_AND_EXPR, unsigned_type_node, tmp3_var,
+	      build_int_cst (unsigned_type_node, accrued_exception_mask));
+  tree update_mask
+    = build2 (MODIFY_EXPR, void_type_node, tmp3_var, masked_tmp3_var);
+  if (SPARC_LOW_FE_EXCEPT_VALUES)
+    {
+      tree shifted_tmp3_var
+	= build2 (RSHIFT_EXPR, unsigned_type_node, tmp3_var,
+		  build_int_cst (unsigned_type_node, 5));
+      tree update_shift
+	= build2 (MODIFY_EXPR, void_type_node, tmp3_var, shifted_tmp3_var);
+      update_mask = compound_expr (update_mask, update_shift);
+    }
+
+  tree atomic_feraiseexcept
+    = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
+  tree update_call
+    = build_call_expr (atomic_feraiseexcept, 1,
+		       fold_convert (integer_type_node, tmp3_var));
+
+  *update
+    = compound_expr (compound_expr (compound_expr (update_stfsr, update_ldfsr),
+				    update_mask),
+		     update_call);
+}
+
 #include "gt-sparc.h"
Index: config/sparc/sparc.h
===================================================================
--- config/sparc/sparc.h	(revision 205689)
+++ config/sparc/sparc.h	(working copy)
@@ -1777,3 +1777,6 @@ extern int sparc_indent_opcode;
 #ifndef SUBTARGET_DEFAULT_MEMORY_MODEL
 #define SUBTARGET_DEFAULT_MEMORY_MODEL	SMM_DEFAULT
 #endif
+
+/* Define this to 1 if the FE_EXCEPT values defined in fenv.h start at 1.  */
+#define SPARC_LOW_FE_EXCEPT_VALUES 0
Index: config/sparc/sol2.h
===================================================================
--- config/sparc/sol2.h	(revision 205689)
+++ config/sparc/sol2.h	(working copy)
@@ -406,3 +406,6 @@ extern const char *host_detect_local_cpu
 
 #undef SUN_INTEGER_MULTIPLY_64
 #define SUN_INTEGER_MULTIPLY_64 1
+
+#undef SPARC_LOW_FE_EXCEPT_VALUES
+#define SPARC_LOW_FE_EXCEPT_VALUES 1
