diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 51fd641773fb20885840707fa03101f7d2e9b9b3..50aebde213958df4bd82b27296cdefc130ead125 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2009-10-09  Richard Guenther  <rguenther@suse.de>
+
+	PR lto/41638
+	* target-def.h (TARGET_BUILTIN_DECL): Define.
+	(TARGET_INITIALIZER): Add TARGET_BUILTIN_DECL.
+	* target.h (struct gcc_target): Add builtin_decl target hook.
+	* doc/tm.texi (TARGET_BUILTIN_DECL): Document.
+	* lto-streamer-in.c (lto_get_builtin_tree): Fix handling of
+	target builtins.
+	* lto-streamer-out.c (lto_output_tree_pointers): Use sorry,
+	not gcc_unreachable.
+	(lto_output_builtin_tree): Sorry if the target does not support
+	streaming target builtins.
+	* config/rs6000/rs6000.c (TARGET_BUILTIN_DECL): Define.
+	(rs6000_builtin_decl): New function.
+	* config/i386/i386.c (TARGET_BUILTIN_DECL): Define.
+	(ix86_builtin_decl): New function.
+
 2009-10-09  Jakub Jelinek  <jakub@redhat.com>
 
 	PR preprocessor/41445
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 9da427faaa76fbd5c552aab5b18178ee078e36d3..0d0628bc3830d8a8d07cbbaafd826e7d4906d79d 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -23443,6 +23443,17 @@ ix86_init_builtins (void)
     ix86_init_builtins_va_builtins_abi ();
 }
 
+/* Return the ix86 builtin for CODE.  */
+
+static tree
+ix86_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  if (code >= IX86_BUILTIN_MAX)
+    return error_mark_node;
+
+  return ix86_builtins[code];
+}
+
 /* Errors in the source file can cause expand_expr to return const0_rtx
    where we expect a vector.  To avoid crashing, use one of the vector
    clear instructions.  */
@@ -29666,6 +29677,8 @@ ix86_enum_va_list (int idx, const char **pname, tree *ptree)
 
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS ix86_init_builtins
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL ix86_builtin_decl
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN ix86_expand_builtin
 
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 333babc255f9f131dd9c2662d466916f178a8335..319af631933f348eebf50b1fad44967bea130631 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -947,6 +947,8 @@ static bool rs6000_builtin_support_vector_misalignment (enum
 static void def_builtin (int, const char *, tree, int);
 static bool rs6000_vector_alignment_reachable (const_tree, bool);
 static void rs6000_init_builtins (void);
+static tree rs6000_builtin_decl (unsigned, bool);
+
 static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
 static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
 static rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
@@ -1332,6 +1334,8 @@ static const struct attribute_spec rs6000_attribute_table[] =
 
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL rs6000_builtin_decl
 
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
@@ -11144,6 +11148,17 @@ rs6000_init_builtins (void)
 #endif
 }
 
+/* Returns the rs6000 builtin decl for CODE.  */
+
+static tree
+rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
+{
+  if (code >= RS6000_BUILTIN_COUNT)
+    return error_mark_node;
+
+  return rs6000_builtin_decls[code];
+}
+
 /* Search through a set of builtins and enable the mask bits.
    DESC is an array of builtins.
    SIZE is the total number of builtins.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 27263d91c590a1351eac2d341506d6c6f51c1942..db42742e9e2f87628e34a68dc9d701b2a56ffe3e 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -10532,6 +10532,16 @@ only language front ends that use those two functions will call
 @samp{TARGET_INIT_BUILTINS}.
 @end deftypefn
 
+@deftypefn {Target Hook} tree TARGET_BUILTIN_FUNCTION (unsigned @var{code}, bool @var{initialize_p})
+Define this hook if you have any machine-specific built-in functions
+that need to be defined.  It should be a function that returns the
+builtin function declaration for the builtin function code @var{code}.
+If there is no such builtin and it cannot be initialized at this time
+if @var{initialize_p} is true the function should return @code{NULL_TREE}.
+If @var{code} is out of range the function should return
+@code{error_mark_node}.
+@end deftypefn
+
 @deftypefn {Target Hook} rtx TARGET_EXPAND_BUILTIN (tree @var{exp}, rtx @var{target}, rtx @var{subtarget}, enum machine_mode @var{mode}, int @var{ignore})
 
 Expand a call to a machine specific built-in function that was set up by
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index f41aa75b8238447dd01ee32dd91a6389a1adb680..d9c207d0b7f09dd6708f99a74987991cc56196be 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -2377,13 +2377,22 @@ lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
   gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD);
 
   fcode = (enum built_in_function) lto_input_uleb128 (ib);
-  gcc_assert (fcode < END_BUILTINS);
 
   ix = lto_input_sleb128 (ib);
   gcc_assert (ix == (int) ix);
 
-  result = built_in_decls[fcode];
-  gcc_assert (result);
+  if (fclass == BUILT_IN_NORMAL)
+    {
+      gcc_assert (fcode < END_BUILTINS);
+      result = built_in_decls[fcode];
+      gcc_assert (result);
+    }
+  else if (fclass == BUILT_IN_MD)
+    {
+      result = targetm.builtin_decl (fcode, true);
+      if (!result || result == error_mark_node)
+	fatal_error ("target specific builtin not available");
+    }
 
   asmname = input_string (data_in, ib);
   if (asmname)
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 499734f4988c5cc1a0eb35835424b5e9a6867596..9d097f0b5033d2f474e6e12c7819f7f62838b614 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -1165,16 +1165,10 @@ lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
     }
 
   if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
-    {
-      /* FIXME lto.  Not handled yet.  */
-      gcc_unreachable ();
-    }
+    sorry ("gimple bytecode streams do not support the optimization attribute");
 
   if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    {
-      /* FIXME lto.  Not handled yet.  */
-      gcc_unreachable ();
-    }
+    sorry ("gimple bytecode streams do not support the target attribute");
 }
 
 
@@ -1234,6 +1228,11 @@ lto_output_builtin_tree (struct output_block *ob, tree expr, int ix)
 {
   gcc_assert (lto_stream_as_builtin_p (expr));
 
+  if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD
+      && !targetm.builtin_decl)
+    sorry ("gimple bytecode streams do not support machine specific builtin "
+	   "functions on this target");
+
   output_record_start (ob, LTO_builtin_decl);
   output_uleb128 (ob, DECL_BUILT_IN_CLASS (expr));
   output_uleb128 (ob, DECL_FUNCTION_CODE (expr));
diff --git a/gcc/target-def.h b/gcc/target-def.h
index 45b7ab7430eaf8c64c91bbc0b8474bd95e57dada..96b43eb9a9ded8aebbab0e04d7a2a7022240ba6d 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -437,6 +437,7 @@
 #define TARGET_EXPAND_BUILTIN default_expand_builtin
 #define TARGET_RESOLVE_OVERLOADED_BUILTIN NULL
 #define TARGET_FOLD_BUILTIN hook_tree_tree_tree_bool_null
+#define TARGET_BUILTIN_DECL NULL
 
 /* In tree-ssa-math-opts.c  */
 #define TARGET_BUILTIN_RECIPROCAL default_builtin_reciprocal
@@ -880,6 +881,7 @@
   TARGET_ALIGN_ANON_BITFIELD,			\
   TARGET_NARROW_VOLATILE_BITFIELD,		\
   TARGET_INIT_BUILTINS,				\
+  TARGET_BUILTIN_DECL,				\
   TARGET_EXPAND_BUILTIN,			\
   TARGET_RESOLVE_OVERLOADED_BUILTIN,		\
   TARGET_FOLD_BUILTIN,				\
diff --git a/gcc/target.h b/gcc/target.h
index f964b6975f82ac3fbdd79840408d0769e3dae8d0..c65063cbfc604a8d9a7ffbb19e8883badb8a79da 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -562,6 +562,12 @@ struct gcc_target
   /* Set up target-specific built-in functions.  */
   void (* init_builtins) (void);
 
+  /* Initialize (if INITIALIZE_P is true) and return the target-specific
+     built-in function decl for CODE.
+     Return NULL if that is not possible.  Return error_mark_node if CODE
+     is outside of the range of valid target builtin function codes.  */
+  tree (* builtin_decl) (unsigned code, bool initialize_p);
+
   /* Expand a target-specific builtin.  */
   rtx (* expand_builtin) (tree exp, rtx target, rtx subtarget,
 			  enum machine_mode mode, int ignore);