diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index 6770eca..2824c96 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -57,32 +57,35 @@ Standard types
 
    Access a specific type.  The available types are:
 
-   =========================================  ================================
-   `enum gcc_jit_types` value                 Meaning
-   =========================================  ================================
-   :c:data:`GCC_JIT_TYPE_VOID`                C's ``void`` type.
-   :c:data:`GCC_JIT_TYPE_VOID_PTR`            C's ``void *``.
-   :c:data:`GCC_JIT_TYPE_BOOL`                C++'s ``bool`` type; also C99's
-                                              ``_Bool`` type, aka ``bool`` if
-                                              using stdbool.h.
-   :c:data:`GCC_JIT_TYPE_CHAR`                C's ``char`` (of some signedness)
-   :c:data:`GCC_JIT_TYPE_SIGNED_CHAR`         C's ``signed char``
-   :c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR`       C's ``unsigned char``
-   :c:data:`GCC_JIT_TYPE_SHORT`               C's ``short`` (signed)
-   :c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT`      C's ``unsigned short``
-   :c:data:`GCC_JIT_TYPE_INT`                 C's ``int`` (signed)
-   :c:data:`GCC_JIT_TYPE_UNSIGNED_INT`        C's ``unsigned int``
-   :c:data:`GCC_JIT_TYPE_LONG`                C's ``long`` (signed)
-   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG`       C's ``unsigned long``
-   :c:data:`GCC_JIT_TYPE_LONG_LONG`           C99's ``long long`` (signed)
-   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG`  C99's ``unsigned long long``
+   ==========================================  ================================
+   `enum gcc_jit_types` value                  Meaning
+   ==========================================  ================================
+   :c:data:`GCC_JIT_TYPE_VOID`                 C's ``void`` type.
+   :c:data:`GCC_JIT_TYPE_VOID_PTR`             C's ``void *``.
+   :c:data:`GCC_JIT_TYPE_BOOL`                 C++'s ``bool`` type; also C99's
+                                               ``_Bool`` type, aka ``bool`` if
+                                               using stdbool.h.
+   :c:data:`GCC_JIT_TYPE_CHAR`                 C's ``char`` (of some signedness)
+   :c:data:`GCC_JIT_TYPE_SIGNED_CHAR`          C's ``signed char``
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR`        C's ``unsigned char``
+   :c:data:`GCC_JIT_TYPE_SHORT`                C's ``short`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT`       C's ``unsigned short``
+   :c:data:`GCC_JIT_TYPE_INT`                  C's ``int`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_INT`         C's ``unsigned int``
+   :c:data:`GCC_JIT_TYPE_LONG`                 C's ``long`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG`        C's ``unsigned long``
+   :c:data:`GCC_JIT_TYPE_LONG_LONG`            C99's ``long long`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG`   C99's ``unsigned long long``
    :c:data:`GCC_JIT_TYPE_FLOAT`
    :c:data:`GCC_JIT_TYPE_DOUBLE`
    :c:data:`GCC_JIT_TYPE_LONG_DOUBLE`
-   :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`      C type: ``(const char *)``
-   :c:data:`GCC_JIT_TYPE_SIZE_T`              C's ``size_t`` type
-   :c:data:`GCC_JIT_TYPE_FILE_PTR`            C type: ``(FILE *)``
-   =========================================  ================================
+   :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`       C type: ``(const char *)``
+   :c:data:`GCC_JIT_TYPE_SIZE_T`               C's ``size_t`` type
+   :c:data:`GCC_JIT_TYPE_FILE_PTR`             C type: ``(FILE *)``
+   :c:data:`GCC_JIT_TYPE_COMPLEX_FLOAT`        C99's ``_Complex float``
+   :c:data:`GCC_JIT_TYPE_COMPLEX_DOUBLE`       C99's ``_Complex double``
+   :c:data:`GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE`  C99's ``_Complex long double``
+   ==========================================  ================================
 
 .. function:: gcc_jit_type *\
               gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
diff --git a/gcc/jit/jit-builtins.c b/gcc/jit/jit-builtins.c
index 9063075..eabf4e4 100644
--- a/gcc/jit/jit-builtins.c
+++ b/gcc/jit/jit-builtins.c
@@ -23,17 +23,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "opts.h"
 #include "tree.h"
 #include "target.h"
+#include "stringpool.h"
 
 #include "jit-common.h"
 #include "jit-builtins.h"
 #include "jit-recording.h"
+#include "jit-playback.h"
 
 namespace gcc {
 
 namespace jit {
 
-namespace recording {
-
 const char *const prefix = "__builtin_";
 const size_t prefix_len = strlen (prefix);
 
@@ -41,9 +41,12 @@ const size_t prefix_len = strlen (prefix);
 struct builtin_data
 {
   const char *name;
+  enum built_in_class fnclass;
   enum jit_builtin_type type;
   bool both_p;
   bool fallback_p;
+  enum built_in_attribute attr;
+  bool implicit_p;
 
   const char *get_asm_name () const
   {
@@ -54,8 +57,9 @@ struct builtin_data
   }
 };
 
-#define DEF_BUILTIN(X, NAME, C, TYPE, LT, BOTH_P, FALLBACK_P, NA, AT, IM, COND)\
-  {NAME, TYPE, BOTH_P, FALLBACK_P},
+#define DEF_BUILTIN(X, NAME, CLASS, TYPE, LT, BOTH_P, FALLBACK_P, \
+		    NONANSI_P, ATTRS, IMPLICIT, COND)		  \
+  {NAME, CLASS, TYPE, BOTH_P, FALLBACK_P, ATTRS, IMPLICIT},
 static const struct builtin_data builtin_data[] =
 {
 #include "builtins.def"
@@ -130,20 +134,21 @@ find_builtin_by_name (const char *in_name,
 
 // class builtins_manager
 
-/* Constructor for gcc::jit::recording::builtins_manager.  */
+/* Constructor for gcc::jit::builtins_manager.  */
 
-builtins_manager::builtins_manager (context *ctxt)
+builtins_manager::builtins_manager (recording::context *ctxt)
   : m_ctxt (ctxt)
 {
   memset (m_types, 0, sizeof (m_types));
   memset (m_builtin_functions, 0, sizeof (m_builtin_functions));
+  memset (m_attributes, 0, sizeof (m_attributes));
 }
 
 /* Locate a builtin function by name.
    Create a recording::function of the appropriate type, reusing them
    if they've already been seen.  */
 
-function *
+recording::function *
 builtins_manager::get_builtin_function (const char *name)
 {
   enum built_in_function builtin_id;
@@ -153,6 +158,16 @@ builtins_manager::get_builtin_function (const char *name)
       return NULL;
     }
 
+  return get_builtin_function_by_id (builtin_id);
+}
+
+/* Locate a builtin function by id.
+   Create a recording::function of the appropriate type, reusing them
+   if they've already been seen.  */
+
+recording::function *
+builtins_manager::get_builtin_function_by_id (enum built_in_function builtin_id)
+{
   gcc_assert (builtin_id >= 0);
   gcc_assert (builtin_id < END_BUILTINS);
 
@@ -160,7 +175,7 @@ builtins_manager::get_builtin_function (const char *name)
      the same id on a context give back the same object.  */
   if (!m_builtin_functions[builtin_id])
     {
-      function *fn = make_builtin_function (builtin_id);
+      recording::function *fn = make_builtin_function (builtin_id);
       if (fn)
 	{
 	  m_builtin_functions[builtin_id] = fn;
@@ -173,23 +188,23 @@ builtins_manager::get_builtin_function (const char *name)
 
 /* Create the recording::function for a given builtin function, by ID.  */
 
-function *
+recording::function *
 builtins_manager::make_builtin_function (enum built_in_function builtin_id)
 {
   const struct builtin_data& bd = builtin_data[builtin_id];
   enum jit_builtin_type type_id = bd.type;
-  type *t = get_type (type_id);
+  recording::type *t = get_type (type_id);
   if (!t)
     return NULL;
-  function_type *func_type = t->as_a_function_type ();
+  recording::function_type *func_type = t->as_a_function_type ();
   if (!func_type)
     return NULL;
 
-  vec<type *> param_types = func_type->get_param_types ();
+  vec<recording::type *> param_types = func_type->get_param_types ();
   recording::param **params = new recording::param *[param_types.length ()];
 
   int i;
-  type *param_type;
+  recording::type *param_type;
   FOR_EACH_VEC_ELT (param_types, i, param_type)
     {
       char buf[16];
@@ -199,24 +214,47 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id)
 				     buf);
     }
   const char *asm_name = bd.get_asm_name ();
-  function *result =
-    new function (m_ctxt,
-		  NULL,
-		  GCC_JIT_FUNCTION_IMPORTED, // FIXME
-		  func_type->get_return_type (),
-		  m_ctxt->new_string (asm_name),
-		  param_types.length (),
-		  params,
-		  func_type->is_variadic (),
-		  builtin_id);
+  recording::function *result =
+    new recording::function (m_ctxt,
+			     NULL,
+			     GCC_JIT_FUNCTION_IMPORTED, // FIXME
+			     func_type->get_return_type (),
+			     m_ctxt->new_string (asm_name),
+			     param_types.length (),
+			     params,
+			     func_type->is_variadic (),
+			     builtin_id);
   delete[] params;
+
+  /* PR/64020 - If the client code is using builtin cos or sin,
+     tree-ssa-math-opt.c's execute_cse_sincos_1 may attempt
+     to optimize them to use __builtin_cexpi; for this,
+     BUILT_IN_CEXPI needs to exist.
+
+     Hence query the cache for BUILT_IN_CEXPI to ensure it gets
+     built.  */
+  if (builtin_id == BUILT_IN_COS || builtin_id == BUILT_IN_SIN)
+    (void)get_builtin_function_by_id (BUILT_IN_CEXPI);
+
+  /* builtins.c:expand_builtin_cexpi can optimize the various
+     CEXP builtins to SINCOS builtins, and hence we may require
+     SINCOS builtins latter.
+
+     Ensure the appropriate SINCOS builtin exists.  */
+  if (builtin_id == BUILT_IN_CEXPIF)
+    (void)get_builtin_function_by_id (BUILT_IN_SINCOSF);
+  else if (builtin_id == BUILT_IN_CEXPI)
+    (void)get_builtin_function_by_id (BUILT_IN_SINCOS);
+  else if (builtin_id == BUILT_IN_CEXPIL)
+    (void)get_builtin_function_by_id (BUILT_IN_SINCOSL);
+
   return result;
 }
 
 /* Get the recording::type for a given type of builtin function,
    by ID, creating it if it doesn't already exist.  */
 
-type *
+recording::type *
 builtins_manager::get_type (enum jit_builtin_type type_id)
 {
   if (!m_types[type_id])
@@ -226,7 +264,7 @@ builtins_manager::get_type (enum jit_builtin_type type_id)
 
 /* Create the recording::type for a given type of builtin function.  */
 
-type *
+recording::type *
 builtins_manager::make_type (enum jit_builtin_type type_id)
 {
   /* Use builtin-types.def to construct a switch statement, with each
@@ -283,12 +321,15 @@ builtins_manager::make_type (enum jit_builtin_type type_id)
 #include "builtin-types.def"
 
 #undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
 #undef DEF_FUNCTION_TYPE_1
 #undef DEF_FUNCTION_TYPE_2
 #undef DEF_FUNCTION_TYPE_3
 #undef DEF_FUNCTION_TYPE_4
 #undef DEF_FUNCTION_TYPE_5
 #undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_FUNCTION_TYPE_VAR_1
 #undef DEF_FUNCTION_TYPE_VAR_2
@@ -307,7 +348,7 @@ builtins_manager::make_type (enum jit_builtin_type type_id)
 
    Only some types are currently supported.  */
 
-type*
+recording::type*
 builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
 {
   switch (type_id)
@@ -339,9 +380,12 @@ builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
     case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT);
     case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE);
     case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE);
-    // case BT_COMPLEX_FLOAT:
-    // case BT_COMPLEX_DOUBLE:
-    // case BT_COMPLEX_LONGDOUBLE:
+    case BT_COMPLEX_FLOAT:
+      return m_ctxt->get_type (GCC_JIT_TYPE_COMPLEX_FLOAT);
+    case BT_COMPLEX_DOUBLE:
+      return m_ctxt->get_type (GCC_JIT_TYPE_COMPLEX_DOUBLE);
+    case BT_COMPLEX_LONGDOUBLE:
+      return m_ctxt->get_type (GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
     case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
     case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR);
     // case BT_CONST:
@@ -350,7 +394,8 @@ builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
     // case BT_PTRMODE:
     // case BT_INT_PTR:
     // case BT_FLOAT_PTR:
-    // case BT_DOUBLE_PTR:
+    case BT_DOUBLE_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE)->get_pointer ();
     // case BT_CONST_DOUBLE_PTR:
     // case BT_LONGDOUBLE_PTR:
     // case BT_PID:
@@ -378,7 +423,7 @@ builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
 /* Create the recording::function_type for a given function type
    signature.  */
 
-function_type *
+recording::function_type *
 builtins_manager::make_fn_type (enum jit_builtin_type,
 				enum jit_builtin_type return_type_id,
 				bool is_variadic,
@@ -386,9 +431,9 @@ builtins_manager::make_fn_type (enum jit_builtin_type,
 {
   va_list list;
   int i;
-  type **param_types = new type *[num_args];
-  type *return_type = NULL;
-  function_type *result = NULL;
+  recording::type **param_types = new recording::type *[num_args];
+  recording::type *return_type = NULL;
+  recording::function_type *result = NULL;
 
   va_start (list, num_args);
   for (i = 0; i < num_args; ++i)
@@ -417,14 +462,104 @@ builtins_manager::make_fn_type (enum jit_builtin_type,
 
 /* Handler for DEF_POINTER_TYPE within builtins_manager::make_type.  */
 
-type *
+recording::type *
 builtins_manager::make_ptr_type (enum jit_builtin_type,
 				 enum jit_builtin_type other_type_id)
 {
-  type *base_type = get_type (other_type_id);
+  recording::type *base_type = get_type (other_type_id);
   return base_type->get_pointer ();
 }
 
-} // namespace recording
+/* Playback support.  */
+
+/* A builtins_manager is associated with a recording::context
+   and might be reused for multiple compiles on various
+   playback::contexts, perhaps with different options.
+
+   Purge any playback state.  Currently this is just the table of
+   attributes.  */
+
+void
+builtins_manager::finish_playback (void)
+{
+  memset (m_attributes, 0, sizeof (m_attributes));
+}
+
+/* Get the enum built_in_class for BUILTIN_ID.  */
+
+enum built_in_class
+builtins_manager::get_class (enum built_in_function builtin_id)
+{
+  return builtin_data[builtin_id].fnclass;
+}
+
+/* Is BUILTIN_ID implicit?  */
+
+bool
+builtins_manager::implicit_p (enum built_in_function builtin_id)
+{
+  return builtin_data[builtin_id].implicit_p;
+}
+
+/* Get any attributes (in tree form) for the function declaration
+   for BUILTIN_ID.
+
+   These are created on-demand, and cached within the m_attributes
+   array, until finish_playback.  */
+
+tree
+builtins_manager::get_attrs_tree (enum built_in_function builtin_id)
+{
+  enum built_in_attribute attr = builtin_data[builtin_id].attr;
+  return get_attrs_tree (attr);
+}
+
+/* As above, but for an enum built_in_attribute.  */
+
+tree
+builtins_manager::get_attrs_tree (enum built_in_attribute attr)
+{
+  gcc_assert (attr < ATTR_LAST);
+  if (!m_attributes [attr])
+    m_attributes [attr] = make_attrs_tree (attr);
+  return m_attributes [attr];
+}
+
+/* Handle a cache-miss within the m_attributes array by
+   generating the attributes for enum built_in_attribute
+   in tree form.  */
+
+tree
+builtins_manager::make_attrs_tree (enum built_in_attribute attr)
+{
+  switch (attr)
+    {
+      /* Generate cases from builtin-attrs.def.  */
+#define DEF_ATTR_NULL_TREE(ENUM)				\
+      case ENUM: return NULL_TREE;
+#define DEF_ATTR_INT(ENUM, VALUE)				\
+      case ENUM: return build_int_cst (integer_type_node, VALUE);
+#define DEF_ATTR_STRING(ENUM, VALUE)				\
+      case ENUM: return build_string (strlen (VALUE), VALUE);
+#define DEF_ATTR_IDENT(ENUM, STRING)				\
+      case ENUM: return get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)	\
+      case ENUM: return tree_cons (get_attrs_tree (PURPOSE),	\
+				   get_attrs_tree (VALUE),	\
+				   get_attrs_tree (CHAIN));
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+
+    default:
+      /* We somehow got a value not covered by the autogenerated
+	 cases.  */
+      gcc_unreachable ();
+      return NULL;
+    }
+}
+
 } // namespace jit
 } // namespace gcc
diff --git a/gcc/jit/jit-builtins.h b/gcc/jit/jit-builtins.h
index 7c46bfd..abc204d 100644
--- a/gcc/jit/jit-builtins.h
+++ b/gcc/jit/jit-builtins.h
@@ -26,8 +26,6 @@ namespace gcc {
 
 namespace jit {
 
-namespace recording {
-
 /* Create an enum of the builtin types.  */
 
 enum jit_builtin_type
@@ -71,43 +69,91 @@ enum jit_builtin_type
   BT_LAST
 }; /* enum jit_builtin_type */
 
+/* Create an enum of the attributes that can be present on builtins.  */
+
+enum built_in_attribute
+{
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+  ATTR_LAST
+};
+
 /***********************************************************************/
 
 class builtins_manager
 {
 public:
-  builtins_manager (context *ctxt);
+  builtins_manager (recording::context *ctxt);
 
-  function *
+  recording::function *
   get_builtin_function (const char *name);
 
+  static enum built_in_class
+  get_class (enum built_in_function builtin_id);
+
+  static bool
+  implicit_p (enum built_in_function builtin_id);
+
+  tree
+  get_attrs_tree (enum built_in_function builtin_id);
+
+  tree
+  get_attrs_tree (enum built_in_attribute attr);
+
+  void
+  finish_playback (void);
+
 private:
-  function *make_builtin_function (enum built_in_function builtin_id);
+  recording::function *
+  get_builtin_function_by_id (enum built_in_function builtin_id);
+
+  recording::function *
+  make_builtin_function (enum built_in_function builtin_id);
 
-  type *get_type (enum jit_builtin_type type_id);
+  recording::type *
+  get_type (enum jit_builtin_type type_id);
 
-  type *make_type (enum jit_builtin_type type_id);
+  recording::type *
+  make_type (enum jit_builtin_type type_id);
 
-  type*
+  recording::type*
   make_primitive_type (enum jit_builtin_type type_id);
 
-  function_type*
+  recording::function_type*
   make_fn_type (enum jit_builtin_type type_id,
 		enum jit_builtin_type return_type_id,
 		bool is_variadic,
 		int num_args, ...);
 
-  type*
+  recording::type*
   make_ptr_type (enum jit_builtin_type type_id,
 		 enum jit_builtin_type other_type_id);
 
+  tree
+  make_attrs_tree (enum built_in_attribute attr);
+
 private:
-  context *m_ctxt;
-  type *m_types[BT_LAST];
-  function *m_builtin_functions[END_BUILTINS];
+  /* Recording fields.  */
+  recording::context *m_ctxt;
+  recording::type *m_types[BT_LAST];
+  recording::function *m_builtin_functions[END_BUILTINS];
+
+  /* Playback fields.  */
+  /* m_attributes is not GTY-marked, but is only ever used from within
+     the region of playback::context::replay () in which a GC can't
+     happen.  */
+  tree m_attributes[ATTR_LAST];
 };
 
-} // namespace recording
 } // namespace jit
 } // namespace gcc
 
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 58e4a8c..c9dde3e 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 #endif
 
-const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_FILE_PTR + 1;
+const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE + 1;
 
 /* This comment is included by the docs.
 
@@ -97,6 +97,7 @@ namespace jit {
 
 class result;
 class dump;
+class builtins_manager; // declared within jit-builtins.h
 
 namespace recording {
 
@@ -104,7 +105,6 @@ namespace recording {
 
   /* Indentation indicates inheritance: */
   class context;
-  class builtins_manager; // declared within jit-builtins.h
   class memento;
     class string;
     class location;
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index d16b3c4..ecdae80 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -46,10 +46,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "print-tree.h"
 #include "gimplify.h"
 #include "gcc-driver-name.h"
+#include "attribs.h"
 
 #include "jit-common.h"
 #include "jit-playback.h"
 #include "jit-result.h"
+#include "jit-builtins.h"
 
 
 /* gcc::jit::playback::context::build_cast uses the convert.h API,
@@ -198,6 +200,13 @@ get_tree_node_for_type (enum gcc_jit_types type_)
 
     case GCC_JIT_TYPE_FILE_PTR:
       return fileptr_type_node;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+      return complex_float_type_node;
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+      return complex_double_type_node;
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return complex_long_double_type_node;
     }
 
   return NULL;
@@ -399,10 +408,21 @@ new_function (location *loc,
 
   if (builtin_id)
     {
-      DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
       DECL_FUNCTION_CODE (fndecl) = builtin_id;
       gcc_assert (loc == NULL);
       DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
+
+      DECL_BUILT_IN_CLASS (fndecl) =
+	builtins_manager::get_class (builtin_id);
+      set_builtin_decl (builtin_id, fndecl,
+			builtins_manager::implicit_p (builtin_id));
+
+      builtins_manager *bm = get_builtins_manager ();
+      tree attrs = bm->get_attrs_tree (builtin_id);
+      if (attrs)
+	decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
+      else
+	decl_attributes (&fndecl, NULL_TREE, 0);
     }
 
   if (kind != GCC_JIT_FUNCTION_IMPORTED)
@@ -1795,6 +1815,14 @@ replay ()
      refs.  Hence we must stop using them before the GC can run.  */
   m_recording_ctxt->disassociate_from_playback ();
 
+  /* The builtins_manager, if any, is associated with the recording::context
+     and might be reused for future compiles on other playback::contexts,
+     but its m_attributes array is not GTY-labeled and hence will become
+     nonsense if the GC runs.  Purge this state.  */
+  builtins_manager *bm = get_builtins_manager ();
+  if (bm)
+    bm->finish_playback ();
+
   timevar_pop (TV_JIT_REPLAY);
 
   if (!errors_occurred ())
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 25a4c28..02f08ba 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -175,6 +175,11 @@ public:
     return m_recording_ctxt->get_bool_option (opt);
   }
 
+  builtins_manager *get_builtins_manager () const
+  {
+    return m_recording_ctxt->get_builtins_manager ();
+  }
+
   result *
   compile ();
 
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 32bf034..82ec399 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -580,6 +580,25 @@ recording::context::new_function (recording::location *loc,
   return result;
 }
 
+/* Locate the builtins_manager (if any) for this family of contexts,
+   creating it if it doesn't exist already.
+
+   All of the recording contexts in a family share one builtins_manager:
+   if we have a child context, follow the parent links to get the
+   ultimate ancestor context, and look for it/store it there.  */
+
+builtins_manager *
+recording::context::get_builtins_manager ()
+{
+  if (m_parent_ctxt)
+    return m_parent_ctxt->get_builtins_manager ();
+
+  if (!m_builtins_manager)
+    m_builtins_manager = new builtins_manager (this);
+
+  return m_builtins_manager;
+}
+
 /* Get a recording::function instance, which is lazily-created and added
    to the context's lists of mementos.
 
@@ -589,9 +608,8 @@ recording::context::new_function (recording::location *loc,
 recording::function *
 recording::context::get_builtin_function (const char *name)
 {
-  if (!m_builtins_manager)
-    m_builtins_manager = new builtins_manager (this);
-  return m_builtins_manager->get_builtin_function (name);
+  builtins_manager *bm = get_builtins_manager ();
+  return bm->get_builtin_function (name);
 }
 
 /* Create a recording::global instance and add it to this context's list
@@ -1248,6 +1266,9 @@ recording::memento_of_get_type::dereference ()
     case GCC_JIT_TYPE_FLOAT:
     case GCC_JIT_TYPE_DOUBLE:
     case GCC_JIT_TYPE_LONG_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
       /* Not a pointer: */
       return NULL;
 
@@ -1309,6 +1330,11 @@ recording::memento_of_get_type::is_int () const
 
     case GCC_JIT_TYPE_FILE_PTR:
       return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return false;
     }
 }
 
@@ -1357,6 +1383,11 @@ recording::memento_of_get_type::is_float () const
 
     case GCC_JIT_TYPE_FILE_PTR:
       return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return true;
     }
 }
 
@@ -1405,6 +1436,11 @@ recording::memento_of_get_type::is_bool () const
 
     case GCC_JIT_TYPE_FILE_PTR:
       return false;
+
+    case GCC_JIT_TYPE_COMPLEX_FLOAT:
+    case GCC_JIT_TYPE_COMPLEX_DOUBLE:
+    case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
+      return false;
     }
 }
 
@@ -1451,7 +1487,11 @@ static const char * const get_type_strings[] = {
 
   "size_t",  /* GCC_JIT_TYPE_SIZE_T */
 
-  "FILE *"  /* GCC_JIT_TYPE_FILE_PTR */
+  "FILE *",  /* GCC_JIT_TYPE_FILE_PTR */
+
+  "complex float", /* GCC_JIT_TYPE_COMPLEX_FLOAT */
+  "complex double", /* GCC_JIT_TYPE_COMPLEX_DOUBLE */
+  "complex long double"  /* GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE */
 
 };
 
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 1b0ef91..31fb304 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -52,6 +52,9 @@ public:
   context (context *parent_ctxt);
   ~context ();
 
+  builtins_manager *
+  get_builtins_manager ();
+
   void record (memento *m);
   void replay_into (replayer *r);
   void disassociate_from_playback ();
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index e07002d..ed6390e 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -382,7 +382,13 @@ enum gcc_jit_types
   GCC_JIT_TYPE_SIZE_T,
 
  /* C type: (FILE *)  */
-  GCC_JIT_TYPE_FILE_PTR
+  GCC_JIT_TYPE_FILE_PTR,
+
+  /* Complex numbers.  */
+  GCC_JIT_TYPE_COMPLEX_FLOAT,
+  GCC_JIT_TYPE_COMPLEX_DOUBLE,
+  GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE
+
 };
 
 extern gcc_jit_type *
