Patchwork [RFC] Lazy builtins part 2 -- need C++ frontend help and questions on tree layout

login
register
mail settings
Submitter Michael Meissner
Date Oct. 24, 2011, 11:02 p.m.
Message ID <20111024230221.GA18112@hungry-tiger2.westford.ibm.com>
Download mbox | patch
Permalink /patch/121451/
State New
Headers show

Comments

Michael Meissner - Oct. 24, 2011, 11:02 p.m.
This patch adds lazy builtin support for C (by default) and C++ (by option).
At the moment, I have disabled C++ by default because there is a tree layout,
that I can't figure how to avoid C++ from complaining when libcpp/mkdeps.c is
compiled.  The problem is string.h has the following:

/* Find the last occurrence of C in S.  */
#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
extern "C++"
{
extern char *strrchr (char *__s, int __c)
     __THROW __asm ("strrchr") __attribute_pure__ __nonnull ((1));
extern __const char *strrchr (__const char *__s, int __c)
     __THROW __asm ("strrchr") __attribute_pure__ __nonnull ((1));

# ifdef __OPTIMIZE__
__extern_always_inline char *
strrchr (char *__s, int __c) __THROW
{
  return __builtin_strrchr (__s, __c);
}

__extern_always_inline __const char *
strrchr (__const char *__s, int __c) __THROW
{
  return __builtin_strrchr (__s, __c);
}
# endif
}
#else
extern char *strrchr (__const char *__s, int __c)
     __THROW __attribute_pure__ __nonnull ((1));
#endif

And the compiler gives the following error message:

--> ~/fsf-install-x86_64/builtin/bin/g++ -O2 -flazy-builtin -S test-builtin-overload.cc
test-builtin-overload.cc: In function ‘void foo(const char*)’:
test-builtin-overload.cc:44:27: error: call of overloaded ‘strrchr(char*&, char)’ is ambiguous
test-builtin-overload.cc:44:27: note: candidates are:
test-builtin-overload.cc:5:16: note: char* std::strrchr(char*, int)
test-builtin-overload.cc:18:3: note: const char* strrchr(const char*, int)
test-builtin-overload.cc:12:3: note: char* strrchr(char*, int)

I might be missing another function that adds declarations besides
grokdeclarator and start_preparsed_function to put the hooks to create the
builtins, or there is something else I'm missing.

In terms of the layout for the tree structure, I used address_space field as
well as another 8 bits in tree_base to encode the builtin function index and
class.  Now, given that address_space is not allowed for functions, we could
move the function_code and built_in_class fields from from the
tree_function_decl structure to the base structure.  I don't have those changes
in these patches, but it occurred to me as I was adding the support.

I assume when I check in the final changes, people would prefer for me to
delete the -flazy-builtin-debug option which I'm using for debugging right now,
or I can leave it in.

Assuming we can't find a solution for C++ before stage1 closes, is it
acceptable to only do lazy builtins for C and not for C++ by default?  If so, I
will keep the -flazy-builtin option, and document it.

I have the hooks for MD lazy builtins, and that is what I'll cover next.

Jason on IRC mentioned that C++ is creating some psuedo builtins on the fly,
and it might be useful to have front end builtins (there is a code for FE
builtins, but so far no front end emits them).  I suspect Fortran could be
cleaned up also.  Is this desirable to add?  I might not get this all done if
stage 1 closes very soon.  My goal is to get MD builtins first.

As before, my development branch is:
svn+ssh://gcc.gnu.org/svn/gcc/branches/ibm/builtin

[gcc]
2011-10-24  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* tree.h (BUILTIN_CLASS_BITS): Add lazy builtin support that is
	enabled by default for C and disabled for C++. Mark identifier
	nodes for lazy builtin functions, and when the identifier is used
	for the first time time create the function declaration node.
	(ADDRESS_SPACE_BITS): Ditto.
	(BUILTIN_FNCODE_BITS): Ditto.
	(struct tree_base): Ditto.
	(struct tree_function_decl): Ditto.
	(IDENTIFIER_LAZY_BUILTIN_P): Ditto.
	(builtin_info_type): Ditto.
	(builtin_decl_explicit): Ditto.
	(builtin_decl_implicit): Ditto.
	(set_builtin_decl): Ditto.
	(builtin_decl_implicit_p): Ditto.
	(builtin_lazy_function_code): Ditto.
	(builtin_lazy_function_class): Ditto.
	(set_builtin_lazy_function_code): Ditto.
	* langhooks-def.h (lhd_builtin_lazy_create): Ditto.
	(LANG_HOOKS_BUILTIN_LAZY_REGISTER): Ditto.
	(LANG_HOOKS_BUILTIN_LAZY_CREATE): Ditto.
	(LANG_HOOKS_LAZY_BUILTIN_P): Ditto.
	(LANG_HOOKS_INITIALIZER): Ditto.
	* c-objc-common.h (LANG_HOOKS_BUILTIN_LAZY_REGISTER): Ditto.
	(LANG_HOOKS_BUILTIN_LAZY_CREATE): Ditto.
	(LANG_HOOKS_LAZY_BUILTIN_P): Ditto.
	* c-decl.c (lookup_name): Ditto.
	(lookup_name_in_scope): Ditto.
	(c_builtin_function): Ditto.
	(c_builtin_function_ext_scope): Ditto.
	(grokdeclarator): Ditto.
	* langhooks.c (add_builtin_function_common): Ditto.
	(add_builtin_function_ext_scope): Ditto.
	(lhd_builtin_lazy_register): Ditto.
	(builtin_lazy_create): Ditto.
	(lhd_builtin_lazy_create): Ditto.
	* langhooks.h (add_builtin_function_type): Ditto.
	(add_builtin_function): Ditto.
	(add_builtin_function_ext_scope): Ditto.
	(struct lang_hooks): Ditto.
	* common.opt (-flazy-builtin): Ditto.
	(-flazy-builtin-debug): Ditto.
	* langhooks-def.h (LANG_HOOKS_BUILTIN_LAZY_REGISTER): Ditto.
	(LANG_HOOKS_BUILTIN_LAZY_CREATE): Ditto.
	(LANG_HOOKS_LAZY_BUILTIN_P): Ditto.
	(LANG_HOOKS_INITIALIZER): Ditto.

[gcc/c-family]
2011-10-24  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* c-opts.c (c_common_post_options): Add lazy builtin support that
	is enabled by default for C and disabled for C++.  Mark identifier
	nodes for lazy builtin functions, and when the identifier is used
	for the first time time create the function declaration node.
	* c-common.c (builtin_types): Ditto.
	(c_common_add_builtin_function_lazy): Ditto.
	(c_common_builtin_lazy_register): Ditto.
	(c_common_builtin_lazy_create): Ditto.
	(c_common_nodes_and_builtins): Ditto.
	(def_builtin_1): Ditto.
	* c-common.h (c_common_builtin_lazy_register): Ditto.
	(c_common_builtin_lazy_create): Ditto.

[gcc/cp]
2011-10-24  Michael Meissner  <meissner@linux.vnet.ibm.com>

	* decl.c (builtin_function_1): Add lazy builtin support that is
	enabled by default for C and disabled for C++. Mark identifier
	nodes for lazy builtin functions, and when the identifier is used
	for the first time time create the function declaration node.
	(cxx_builtin_function): Ditto.
	(cxx_builtin_function_ext_scope): Ditto.
	(grokdeclarator): Ditto.
	(start_preparsed_function): Ditto.
	* cp-objcp-common.h (LANG_HOOKS_BUILTIN_LAZY_REGISTER): Ditto.
	(LANG_HOOKS_BUILTIN_LAZY_CREATE): Ditto.
	(LANG_HOOKS_LAZY_BUILTIN_P): Ditto.
	* name-lookup.c (lookup_name_real_1): Ditto.

Patch

Index: gcc/c-family/c-opts.c
===================================================================
--- gcc/c-family/c-opts.c	(.../trunk)	(revision 180408)
+++ gcc/c-family/c-opts.c	(.../branches/ibm/builtin)	(revision 180409)
@@ -903,6 +903,12 @@  c_common_post_options (const char **pfil
   if (flag_objc_exceptions && !flag_objc_sjlj_exceptions)
     flag_exceptions = 1;
 
+  /* If -flazy-builtins is -1, let the language decide whether to allow lazy
+     builtins on not.  Right now, it is hard to get all of the details of C++
+     correct, so turn it off for C++.  */
+  if (flag_lazy_builtin < 0)
+    flag_lazy_builtin = lang_hooks.lazy_builtin_p;
+
   /* -Wextra implies the following flags
      unless explicitly overridden.  */
   if (warn_type_limits == -1)
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(.../trunk)	(revision 180408)
+++ gcc/c-family/c-common.c	(.../branches/ibm/builtin)	(revision 180409)
@@ -4488,7 +4488,7 @@  typedef enum c_builtin_type builtin_type
 
 /* A temporary array for c_common_nodes_and_builtins.  Used in
    communication with def_fn_type.  */
-static tree builtin_types[(int) BT_LAST + 1];
+static GTY(()) tree builtin_types[(int) BT_LAST + 1];
 
 /* A helper function for c_common_nodes_and_builtins.  Build function type
    for DEF with return type RET and N arguments.  If VAR is true, then the
@@ -4610,6 +4610,280 @@  c_define_builtins (tree va_list_ref_type
     mudflap_init ();
 }
 
+/* Create builtins in a lazy fashion if the front end supports it, otherwise
+   create the builtin function immediately.  */
+
+static tree
+c_common_add_builtin_function_lazy (const char *name, tree type,
+				    int function_code, enum built_in_class cl,
+				    const char *library_name, tree attrs)
+{
+  bool lazy_p;
+
+  if (flag_lazy_builtin <= 0)
+    lazy_p = false;
+
+  /* Force some builtins used by the optimization passes to be created
+     immediately.  */
+  else if (cl == BUILT_IN_NORMAL)
+    {
+      switch ((enum built_in_function)function_code)
+	{
+	case BUILT_IN_ADJUST_TRAMPOLINE:
+	case BUILT_IN_ALLOCA:
+	case BUILT_IN_ALLOCA_WITH_ALIGN:
+	case BUILT_IN_BSWAP32:
+	case BUILT_IN_BSWAP64:
+	case BUILT_IN_CALLOC:
+	case BUILT_IN_CLEAR_CACHE:
+	case BUILT_IN_FPRINTF:
+	case BUILT_IN_FPRINTF_CHK:
+	case BUILT_IN_FREE:
+	case BUILT_IN_INIT_TRAMPOLINE:
+	case BUILT_IN_LONGJMP:
+	case BUILT_IN_MALLOC:
+	case BUILT_IN_MEMCHR:
+	case BUILT_IN_MEMCPY:
+	case BUILT_IN_MEMCPY_CHK:
+	case BUILT_IN_MEMMOVE:
+	case BUILT_IN_MEMMOVE_CHK:
+	case BUILT_IN_MEMPCPY:
+	case BUILT_IN_MEMPCPY_CHK:
+	case BUILT_IN_MEMSET:
+	case BUILT_IN_MEMSET_CHK:
+	case BUILT_IN_NONLOCAL_GOTO:
+	case BUILT_IN_OBJECT_SIZE:
+	case BUILT_IN_PRINTF:
+	case BUILT_IN_PRINTF_CHK:
+	case BUILT_IN_PROFILE_FUNC_ENTER:
+	case BUILT_IN_PROFILE_FUNC_EXIT:
+	case BUILT_IN_REALLOC:
+	case BUILT_IN_RETURN_ADDRESS:
+	case BUILT_IN_SETJMP:
+	case BUILT_IN_SETJMP_DISPATCHER:
+	case BUILT_IN_SETJMP_RECEIVER:
+	case BUILT_IN_SETJMP_SETUP:
+	case BUILT_IN_SNPRINTF_CHK:
+	case BUILT_IN_SPRINTF:
+	case BUILT_IN_SPRINTF_CHK:
+	case BUILT_IN_STACK_RESTORE:
+	case BUILT_IN_STACK_SAVE:
+	case BUILT_IN_STPCPY:
+	case BUILT_IN_STPCPY_CHK:
+	case BUILT_IN_STRCAT:
+	case BUILT_IN_STRCAT_CHK:
+	case BUILT_IN_STRCHR:
+	case BUILT_IN_STRCMP:
+	case BUILT_IN_STRCPY:
+	case BUILT_IN_STRCPY_CHK:
+	case BUILT_IN_STRCSPN:
+	case BUILT_IN_STRLEN:
+	case BUILT_IN_STRNCAT:
+	case BUILT_IN_STRNCAT_CHK:
+	case BUILT_IN_STRNCPY:
+	case BUILT_IN_STRNCPY_CHK:
+	case BUILT_IN_VFPRINTF_CHK:
+	case BUILT_IN_VPRINTF:
+	case BUILT_IN_VPRINTF_CHK:
+	case BUILT_IN_VSNPRINTF_CHK:
+	case BUILT_IN_VSPRINTF_CHK:
+	  lazy_p = false;
+	  break;
+
+	default:
+	  lazy_p = true;
+	  break;
+	}
+    }
+
+  else if (cl == BUILT_IN_MD)
+    lazy_p = true;
+
+  else
+    lazy_p = false;
+
+  gcc_assert (IN_RANGE (function_code, 0, (1 << BUILTIN_FNCODE_BITS) - 1));
+
+  /* If the identifier has already been created, do not create a lazy builtin
+     for the identifier.  */
+  if (lazy_p)
+    {
+      tree id = maybe_get_identifier (name);
+      if (id != NULL_TREE)
+	lazy_p = false;
+    }
+
+  /* If we can't add the function lazily, add it immediately.  */
+  if (!lazy_p)
+    return add_builtin_function (name, type, function_code, cl, library_name,
+				 attrs);
+
+  /* Mark the identiifer so the next use during parsing adds the function
+     declaration.  */
+  return c_common_builtin_lazy_register (name, function_code, cl);
+}
+
+/* Register an identifier that is a lazy builtin that will be expanded by
+   calling the builtin_lazy_create builtin.  If the front does not support lazy
+   builtins, only MD builtins are supported, and they are expanded immediately.
+   When the front end or back end hook is called, it is expected that all
+   varients of the builtin function will be created.  */
+
+tree
+c_common_builtin_lazy_register (const char *name,
+				unsigned uns_fncode,
+				enum built_in_class cl)
+{
+  /* Mark the identiifer so the next use during parsing adds the function
+     declaration.  */
+  tree id = get_identifier (name);
+
+  gcc_checking_assert (!IDENTIFIER_LAZY_BUILTIN_P (id));
+  gcc_checking_assert (builtin_lazy_function_code (id) == 0);
+  IDENTIFIER_LAZY_BUILTIN_P (id) = 1;
+
+  set_builtin_lazy_function_code (id, uns_fncode, cl);
+
+  if (flag_lazy_builtin_debug)
+    fprintf (stderr,
+	     "---c_common_builtin_lazy_register (%s, %s, %u [%s])\n",
+	     name, built_in_class_names[(int)cl], uns_fncode,
+	     (cl == BUILT_IN_NORMAL) ? built_in_names[uns_fncode] : "---");
+
+  return id;
+}
+
+/* Language hook to create a standard or front end lazy builtin with identifier
+   IDENT.  Machine builtins go through the targetm builtin_decl hook
+   instead of going here.  At the moment, there are no front end builtins.  */
+
+tree
+c_common_builtin_lazy_create (tree id,
+			      unsigned uns_fncode,
+			      enum built_in_class cl)
+{
+  const char *main_name = NULL;
+  const char *name = IDENTIFIER_POINTER (id);
+  const char *lib_name = NULL;
+  enum c_builtin_type fntype = BT_LAST;
+  enum built_in_attribute attrs = ATTR_LAST;
+  enum built_in_function fncode = (enum built_in_function)uns_fncode;
+  bool return_lib_p = false;
+  bool implicit_p = false;
+  bool fallback_p = false;
+  tree decl, id2, lib_decl;
+  tree fntype_tree;
+  tree fnattr_tree;
+
+  gcc_checking_assert (IDENTIFIER_LAZY_BUILTIN_P (id));
+  gcc_checking_assert (cl == BUILT_IN_NORMAL);
+
+  switch (fncode)
+    {
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \
+		    NONANSI_P, ATTRS, IMPLICIT, COND)			\
+    case ENUM:								\
+      if (NAME && COND)							\
+	{								\
+	  main_name = NAME;						\
+	  fntype = TYPE;						\
+	  attrs = ATTRS;						\
+	  implicit_p = IMPLICIT;					\
+	  fallback_p = FALLBACK_P;					\
+	}								\
+      break;
+
+#include "builtins.def"
+#undef DEF_BUILTIN
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* If this is the __builtin_<xxx> name and it has already been created, just
+     return that.  */
+  gcc_assert (main_name != NULL);
+  if (builtin_info.decl[uns_fncode] != NULL_TREE
+      && TREE_CODE (builtin_info.decl[uns_fncode]) == FUNCTION_DECL
+      && !strcmp (name, main_name))
+    {
+      if (flag_lazy_builtin_debug)
+	fprintf (stderr, "---c_common_builtin_lazy_create (%s, old decl)\n",
+		 name);
+
+      return builtin_info.decl[uns_fncode];
+    }
+
+  if (!fallback_p)
+    lib_name = NULL;
+
+  else
+    {
+      lib_name = main_name + strlen ("__builtin_");
+
+      /* If the decl using the library name has been created, use that.  */
+      if (builtin_info.lib_decl[uns_fncode] != NULL_TREE
+	  && TREE_CODE (builtin_info.lib_decl[uns_fncode]) == FUNCTION_DECL
+	  && !strcmp (name, lib_name))
+	{
+	  if (flag_lazy_builtin_debug)
+	    fprintf (stderr,
+		     "---c_common_builtin_lazy_create (%s, old lib decl)\n",
+		     name);
+
+	  return builtin_info.lib_decl[uns_fncode];
+	}
+    }
+
+  if (flag_lazy_builtin_debug)
+    fprintf (stderr,
+	     "---c_common_builtin_lazy_create (%s, %s, %s, lib=%s%s%s)\n",
+	     main_name,
+	     (cl == BUILT_IN_NORMAL) ? built_in_names[uns_fncode] : "---",
+	     built_in_class_names[(int)cl],
+	     (lib_name ? lib_name : "<null>"),
+	     (implicit_p ? ", implicit" : ""),
+	     (fallback_p ? ", fallback" : ""));
+
+  fntype_tree = builtin_types[(int) fntype];
+  fnattr_tree = built_in_attributes[(int) attrs];
+
+  /* Turn off the lazy builtin flag now before calling add_builtin so that we
+     don't get an endless loop.  */
+  id2 = builtin_info.decl[uns_fncode];
+  if (id2 && TREE_CODE (id2) == IDENTIFIER_NODE)
+    {
+      IDENTIFIER_LAZY_BUILTIN_P (id2) = 0;
+      set_builtin_lazy_function_code (id2, 0, NOT_BUILT_IN);
+    }
+
+  id2 = builtin_info.lib_decl[uns_fncode];
+  if (id2 && TREE_CODE (id2) == IDENTIFIER_NODE)
+    {
+      IDENTIFIER_LAZY_BUILTIN_P (id2) = 0;
+      set_builtin_lazy_function_code (id2, 0, NOT_BUILT_IN);
+
+      if (id == id2)
+	return_lib_p = true;
+    }
+
+  /* Now create the explicit implicit builtin and maybe the implicit library
+     builtin function.  */
+  decl = add_builtin_function_ext_scope (main_name, fntype_tree, fncode, cl,
+					 lib_name, fnattr_tree);
+
+  if (builtin_info.lib_decl[uns_fncode] != NULL_TREE && lib_name != NULL)
+    lib_decl = add_builtin_function_ext_scope (lib_name, fntype_tree, fncode,
+					       cl, NULL, fnattr_tree);
+  else
+    lib_decl = NULL_TREE;
+
+  builtin_info.decl[uns_fncode] = decl;
+  builtin_info.lib_decl[uns_fncode] = lib_decl;
+  builtin_info.implicit_p[uns_fncode] = implicit_p;
+  return (return_lib_p && lib_decl) ? lib_decl : decl;
+}
+
 /* Like get_identifier, but avoid warnings about null arguments when
    the argument may be NULL for targets where GCC lacks stdint.h type
    information.  */
@@ -5058,9 +5332,6 @@  c_common_nodes_and_builtins (void)
      not shared.  */
   null_node = make_node (INTEGER_CST);
   TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
-
-  /* Since builtin_types isn't gc'ed, don't export these nodes.  */
-  memset (builtin_types, 0, sizeof (builtin_types));
 }
 
 /* The number of named compound-literals generated thus far.  */
@@ -5145,8 +5416,9 @@  def_builtin_1 (enum built_in_function fn
 	       bool both_p, bool fallback_p, bool nonansi_p,
 	       tree fnattrs, bool implicit_p)
 {
-  tree decl;
+  tree decl, lib_decl;
   const char *libname;
+  size_t uns_fncode = (size_t)fncode;
 
   if (fntype == error_mark_node)
     return;
@@ -5156,17 +5428,33 @@  def_builtin_1 (enum built_in_function fn
 			   strlen ("__builtin_")));
 
   libname = name + strlen ("__builtin_");
-  decl = add_builtin_function (name, fntype, fncode, fnclass,
-			       (fallback_p ? libname : NULL),
-			       fnattrs);
 
-  set_builtin_decl (fncode, decl, implicit_p);
+  /* If there was a reference to a lazy builtin function via either the
+     builtin_decl_explict or builtin_decl_implicit functions that the code
+     generator might care about, such as memcpy, we might have created a node
+     with the appropriate type, but that wasn't linked into the front end's
+     binding.  If so, use that node, and just add it to the binding.  Otherwise
+     create a new node.  */
+  decl = builtin_info.decl[(int)fncode];
+  if (!decl || TREE_CODE (decl) != FUNCTION_DECL)
+    decl = c_common_add_builtin_function_lazy (name, fntype, fncode, fnclass,
+					       (fallback_p ? libname : NULL),
+					       fnattrs);
+
+  else
+    decl = lang_hooks.builtin_function (decl);
 
   if (both_p
       && !flag_no_builtin && !builtin_function_disabled_p (libname)
       && !(nonansi_p && flag_no_nonansi_builtin))
-    add_builtin_function (libname, libtype, fncode, fnclass,
-			  NULL, fnattrs);
+    lib_decl = c_common_add_builtin_function_lazy (libname, libtype, fncode,
+						   fnclass, NULL, fnattrs);
+  else
+    lib_decl = NULL_TREE;
+
+  builtin_info.decl[uns_fncode] = decl;
+  builtin_info.lib_decl[uns_fncode] = lib_decl;
+  builtin_info.implicit_p[uns_fncode] = implicit_p;
 }
 
 /* Nonzero if the type T promotes to int.  This is (nearly) the
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(.../trunk)	(revision 180408)
+++ gcc/c-family/c-common.h	(.../branches/ibm/builtin)	(revision 180409)
@@ -803,6 +803,15 @@  extern tree c_build_qualified_type (tree
    frontends.  */
 extern void c_common_nodes_and_builtins (void);
 
+/* Language hook to register lazy builtin with identifier IDENT.  */
+extern tree c_common_builtin_lazy_register (const char *name,
+					    unsigned fncode,
+					    enum built_in_class cl);
+
+/* Language hook to create lazy builtin with identifier IDENT.  */
+extern tree c_common_builtin_lazy_create (tree id, unsigned fncode,
+					  enum built_in_class cl);
+
 extern void disable_builtin_function (const char *);
 
 extern void set_compound_literal_name (tree decl);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(.../trunk)	(revision 180408)
+++ gcc/tree.h	(.../branches/ibm/builtin)	(revision 180409)
@@ -281,6 +281,9 @@  enum built_in_class
    to the enum since we need the enumb to fit in 2 bits.  */
 #define BUILT_IN_LAST (BUILT_IN_NORMAL + 1)
 
+/* Number of bits to hold a built_in_class enum.  */
+#define BUILTIN_CLASS_BITS 2
+
 /* Names for the above.  */
 extern const char *const built_in_class_names[4];
 
@@ -465,12 +468,25 @@  struct GTY(()) tree_base {
   unsigned user_align : 1;
   unsigned nameless_flag : 1;
 
-  unsigned spare : 12;
+  unsigned spare : 4;
+
+  /* Encode high part of lazy builtin function index for identifier node.  This
+     field could modified, and the encoding scheme for lazy builtins changed to
+     use discrete bits if we need more bits.  */
+
+#define LAZY_BUILTIN_BITS (8 - BUILTIN_CLASS_BITS)
+
+  ENUM_BITFIELD(built_in_class) built_in_class : BUILTIN_CLASS_BITS;
+  unsigned lazy_builtin : LAZY_BUILTIN_BITS;
 
-  /* This field is only used with type nodes; the only reason it is present
-     in tree_base instead of tree_type is to save space.  The size of the
-     field must be large enough to hold addr_space_t values.  */
-  unsigned address_space : 8;
+#define ADDRESS_SPACE_BITS 8
+
+  /* This field is only used with type nodes; the only reason it is present in
+     tree_base instead of tree_type is to save space.  The size of the field
+     must be large enough to hold addr_space_t values.  The lazy builtin
+     function encoding also uses this field only in identifier nodes for the
+     low part of the builtin function index.  */
+  unsigned address_space : ADDRESS_SPACE_BITS;
 };
 
 struct GTY(()) tree_typed {
@@ -595,6 +611,9 @@  struct GTY(()) tree_common {
        CALL_ALLOCA_FOR_VAR_P in
            CALL_EXPR
 
+       IDENTIFIER_LAZY_BUILTIN in
+	   IDENTIFIER_NODE
+
    side_effects_flag:
 
        TREE_SIDE_EFFECTS in
@@ -3489,6 +3508,9 @@  extern VEC(tree, gc) **decl_debug_args_i
 #define DECL_FUNCTION_SPECIFIC_OPTIMIZATION(NODE) \
    (FUNCTION_DECL_CHECK (NODE)->function_decl.function_specific_optimization)
 
+/* Number of bits used to hold the builtin function index.  */
+#define BUILTIN_FNCODE_BITS 11
+
 /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
    arguments/result/saved_tree fields by front ends.   It was either inherit
    FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL,
@@ -3510,8 +3532,8 @@  struct GTY(()) tree_function_decl {
      DECL_FUNCTION_CODE.  Otherwise unused.
      ???  The bitfield needs to be able to hold all target function
 	  codes as well.  */
-  ENUM_BITFIELD(built_in_function) function_code : 11;
-  ENUM_BITFIELD(built_in_class) built_in_class : 2;
+  ENUM_BITFIELD(built_in_function) function_code : BUILTIN_FNCODE_BITS;
+  ENUM_BITFIELD(built_in_class) built_in_class : BUILTIN_CLASS_BITS;
 
   unsigned static_ctor_flag : 1;
   unsigned static_dtor_flag : 1;
@@ -5928,17 +5950,29 @@  extern bool block_may_fallthru (const_tr
 
 /* Functional interface to the builtin functions.  */
 
-/* The builtin_info structure holds the FUNCTION_DECL of the standard builtin
-   function, and a flag that says if the function is available implicitly, or
-   whether the user has to code explicit calls to __builtin_<xxx>.  */
+/* Mark that an identifier_node is a lazy builtin.  */
+#define IDENTIFIER_LAZY_BUILTIN_P(NODE) \
+  (IDENTIFIER_NODE_CHECK (NODE)->base.protected_flag)
+
+/* The builtin_info structure holds the FUNCTION_DECL/IDENTIFIER_NODE of the
+   standard builtin function and the library function, the and a flag that says
+   if the function is available implicitly, or whether the user has to code
+   explicit calls to __builtin_<xxx>.  If the function is to be created when
+   used, the IDENTIFIER_NODE will be stored in the decl and lib_decl
+   fields.  */
 
 typedef struct GTY(()) builtin_info_type_d {
-  tree decl[(int)END_BUILTINS];
-  bool implicit_p[(int)END_BUILTINS];
+  tree decl[(int)END_BUILTINS];		/* explict function.  */
+  tree lib_decl[(int)END_BUILTINS];	/* library function.  */
+  bool implicit_p[(int)END_BUILTINS];	/* function declared implicitly.  */
 } builtin_info_type;
 
 extern GTY(()) builtin_info_type builtin_info;
 
+/* Call front end for standard builtins or back end hook for machine dependent
+   builtins that are created on demand..  */
+extern tree builtin_lazy_create (tree);
+
 /* Valid builtin number.  */
 #define BUILTIN_VALID_P(FNCODE) \
   (IN_RANGE ((int)FNCODE, ((int)BUILT_IN_NONE) + 1, ((int) END_BUILTINS) - 1))
@@ -5947,9 +5981,15 @@  extern GTY(()) builtin_info_type builtin
 static inline tree
 builtin_decl_explicit (enum built_in_function fncode)
 {
+  tree bfn;
+
   gcc_checking_assert (BUILTIN_VALID_P (fncode));
 
-  return builtin_info.decl[(size_t)fncode];
+  bfn = builtin_info.decl[(size_t)fncode];
+  if (bfn && TREE_CODE (bfn) == IDENTIFIER_NODE)
+    bfn = builtin_lazy_create (bfn);
+
+  return bfn;
 }
 
 /* Return the tree node for an implicit builtin function or NULL.  */
@@ -5957,12 +5997,17 @@  static inline tree
 builtin_decl_implicit (enum built_in_function fncode)
 {
   size_t uns_fncode = (size_t)fncode;
-  gcc_checking_assert (BUILTIN_VALID_P (fncode));
+  tree bfn;
 
+  gcc_checking_assert (BUILTIN_VALID_P (fncode));
   if (!builtin_info.implicit_p[uns_fncode])
     return NULL_TREE;
 
-  return builtin_info.decl[uns_fncode];
+  bfn = builtin_info.decl[uns_fncode];
+  if (bfn && TREE_CODE (bfn) == IDENTIFIER_NODE)
+    bfn = builtin_lazy_create (bfn);
+
+  return bfn;
 }
 
 /* Set explicit builtin function nodes and whether it is an implicit
@@ -5971,13 +6016,14 @@  builtin_decl_implicit (enum built_in_fun
 static inline void
 set_builtin_decl (enum built_in_function fncode, tree decl, bool implicit_p)
 {
-  size_t ufncode = (size_t)fncode;
+  size_t uns_fncode = (size_t)fncode;
 
   gcc_checking_assert (BUILTIN_VALID_P (fncode)
 		       && (decl != NULL_TREE || !implicit_p));
 
-  builtin_info.decl[ufncode] = decl;
-  builtin_info.implicit_p[ufncode] = implicit_p;
+  builtin_info.decl[uns_fncode] = decl;
+  builtin_info.lib_decl[uns_fncode] = NULL_TREE;
+  builtin_info.implicit_p[uns_fncode] = implicit_p;
 }
 
 /* Set the implicit flag for a builtin function.  */
@@ -6015,4 +6061,41 @@  builtin_decl_implicit_p (enum built_in_f
 	  && builtin_info.implicit_p[uns_fncode]);
 }
 
+/* Return the function code of a lazy builtin encoded in the identifier node in
+   two parts, using 2 bits for the class, and the 6 bit lazy_builtin and
+   address_space fields in the tree_base type.  */
+
+static inline unsigned
+builtin_lazy_function_code (tree node)
+{
+  tree lnode = IDENTIFIER_NODE_CHECK (node);
+  return (((lnode->base.lazy_builtin) << ADDRESS_SPACE_BITS)
+	  | (lnode->base.address_space));
+}
+
+/* Return the builtin class for a lazy builtin.  */
+
+static inline enum built_in_class
+builtin_lazy_function_class (tree node)
+{
+  return (enum built_in_class) IDENTIFIER_NODE_CHECK (node)->base.built_in_class;
+}
+
+/* Encode function id and builtin class in an identifier node.  */
+
+static inline void
+set_builtin_lazy_function_code (tree node, unsigned value,
+				enum built_in_class bclass)
+{
+  tree inode = IDENTIFIER_NODE_CHECK (node);
+  inode->base.lazy_builtin = value >> ADDRESS_SPACE_BITS;
+  inode->base.address_space = (value & ((1u << ADDRESS_SPACE_BITS) - 1));
+  inode->base.built_in_class = bclass;
+
+  /* Make sure the address_space and rid_code fields didn't change sizes and we
+     don't get the same value back.  */
+  gcc_checking_assert (value == builtin_lazy_function_code (node));
+  gcc_checking_assert ((int)bclass == (int)builtin_lazy_function_class (node));
+}
+
 #endif  /* GCC_TREE_H  */
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(.../trunk)	(revision 180408)
+++ gcc/cp/decl.c	(.../branches/ibm/builtin)	(revision 180409)
@@ -76,7 +76,7 @@  static tree grokvardecl (tree, tree, con
 			 int, int, tree);
 static int check_static_variable_definition (tree, tree);
 static void record_unknown_type (tree, const char *);
-static tree builtin_function_1 (tree, tree, bool);
+static tree builtin_function_1 (tree, tree, bool, bool);
 static tree build_library_fn_1 (tree, enum tree_code, tree);
 static int member_function_or_else (tree, tree, enum overload_flags);
 static void bad_specifiers (tree, enum bad_spec_place, int, int, int, int,
@@ -3812,8 +3812,13 @@  cp_make_fname_decl (location_t loc, tree
   return decl;
 }
 
+/* Finish creating a builtin function DECL with context CONTEXT.  If IS_GLOBAL
+   is true, we want to create the function at the global scope level, and it is
+   used for creating lazy builtins as they are needed.  If IS_STD is true, we
+   are creating a lazy builtin that must be in the std namespace.  */
+
 static tree
-builtin_function_1 (tree decl, tree context, bool is_global)
+builtin_function_1 (tree decl, tree context, bool is_global, bool is_std)
 {
   tree          id = DECL_NAME (decl);
   const char *name = IDENTIFIER_POINTER (id);
@@ -3830,8 +3835,13 @@  builtin_function_1 (tree decl, tree cont
 
   DECL_CONTEXT (decl) = context;
 
-  if (is_global)
-    pushdecl_top_level (decl);
+  /* Pushdecl_top_level and pushdecl_with_scope might merge the declaration
+     with an existing declaration, and return the existing declaration, instead
+     of the declaration we just created.  */
+  if (is_std)
+    decl = pushdecl_with_scope (decl, NAMESPACE_LEVEL (std_node), false);
+  else if (is_global)
+    decl = pushdecl_top_level (decl);
   else
     pushdecl (decl);
 
@@ -3866,18 +3876,17 @@  cxx_builtin_function (tree decl)
     {
       tree decl2 = copy_node(decl);
       push_namespace (std_identifier);
-      builtin_function_1 (decl2, std_node, false);
+      builtin_function_1 (decl2, std_node, false, false);
       pop_namespace ();
     }
 
-  return builtin_function_1 (decl, NULL_TREE, false);
+  return builtin_function_1 (decl, NULL_TREE, false, false);
 }
 
-/* Like cxx_builtin_function, but guarantee the function is added to the global
-   scope.  This is to allow function specific options to add new machine
-   dependent builtins when the target ISA changes via attribute((target(...)))
-   which saves space on program startup if the program does not use non-generic
-   ISAs.  */
+/* Like cxx_builtin_function, but make sure the scope is the external scope.
+   This is used for lazy builtin functions that are created when the identifier
+   is frist used.  Some front ends might use the same target hook for this and
+   builtin_function.  */
 
 tree
 cxx_builtin_function_ext_scope (tree decl)
@@ -3885,17 +3894,24 @@  cxx_builtin_function_ext_scope (tree dec
 
   tree          id = DECL_NAME (decl);
   const char *name = IDENTIFIER_POINTER (id);
+
+  if (flag_lazy_builtin_debug)
+    fprintf (stderr, "---cxx_builtin_function_ext_scope (%s, decl=%p, %s, "
+	     "fncode=%d [%s])\n",
+	     name,
+	     (void *)decl,
+	     built_in_class_names[(int) DECL_BUILT_IN_CLASS (decl)],
+	     (int)DECL_FUNCTION_CODE (decl),
+	     ((DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+	      ? built_in_names[(int)DECL_FUNCTION_CODE (decl)]
+	      : "---"));
+
   /* All builtins that don't begin with an '_' should additionally
      go in the 'std' namespace.  */
   if (name[0] != '_')
-    {
-      tree decl2 = copy_node(decl);
-      push_namespace (std_identifier);
-      builtin_function_1 (decl2, std_node, true);
-      pop_namespace ();
-    }
+    builtin_function_1 (copy_node (decl), std_node, true, true);
 
-  return builtin_function_1 (decl, NULL_TREE, true);
+  return builtin_function_1 (decl, std_node, true, false);
 }
 
 /* Generate a FUNCTION_DECL with the typical flags for a runtime library
@@ -8517,6 +8533,21 @@  grokdeclarator (const cp_declarator *dec
 	break;
     }
 
+
+  /* If this identifier is a lazy builtin whose function type has not yet been
+     created, create it now before adding the declaration.  */
+  if (name)
+    {
+      tree tname = get_identifier (name);
+      if (tname && IDENTIFIER_LAZY_BUILTIN_P (tname))
+	{
+	  if (flag_lazy_builtin_debug)
+	    fprintf (stderr, "---grokdeclarator (%s)\n", name);
+
+	  (void) builtin_lazy_create (tname);
+	}
+    }
+
   /* [dcl.fct.edf]
 
      The declarator in a function-definition shall have the form
@@ -12477,6 +12508,7 @@  start_preparsed_function (tree decl1, tr
   tree ctype = NULL_TREE;
   tree fntype;
   tree restype;
+  tree name;
   int doing_friend = 0;
   cp_binding_level *bl;
   tree current_function_parms;
@@ -12488,6 +12520,18 @@  start_preparsed_function (tree decl1, tr
   gcc_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE);
   gcc_assert (TREE_CHAIN (void_list_node) == NULL_TREE);
 
+  /* If function name is a lazy builtin whose function type has not yet been
+     created, create it now before compiling the current function.  */
+  name = DECL_NAME (decl1);
+  if (name && IDENTIFIER_LAZY_BUILTIN_P (name))
+    {
+      if (flag_lazy_builtin_debug)
+	fprintf (stderr, "---start_preparsed_function (%s)\n",
+		 IDENTIFIER_POINTER (name));
+
+      (void) builtin_lazy_create (name);
+    }
+
   fntype = TREE_TYPE (decl1);
   if (TREE_CODE (fntype) == METHOD_TYPE)
     ctype = TYPE_METHOD_BASETYPE (fntype);
Index: gcc/cp/cp-objcp-common.h
===================================================================
--- gcc/cp/cp-objcp-common.h	(.../trunk)	(revision 180408)
+++ gcc/cp/cp-objcp-common.h	(.../branches/ibm/builtin)	(revision 180409)
@@ -90,11 +90,20 @@  extern void cp_common_init_ts (void);
 #define LANG_HOOKS_BUILTIN_FUNCTION cxx_builtin_function
 #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
 #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE cxx_builtin_function_ext_scope
+#undef	LANG_HOOKS_BUILTIN_LAZY_REGISTER
+#define	LANG_HOOKS_BUILTIN_LAZY_REGISTER c_common_builtin_lazy_register
+#undef	LANG_HOOKS_BUILTIN_LAZY_CREATE
+#define	LANG_HOOKS_BUILTIN_LAZY_CREATE c_common_builtin_lazy_create
 #undef	LANG_HOOKS_TYPE_HASH_EQ
 #define LANG_HOOKS_TYPE_HASH_EQ	cxx_type_hash_eq
 #undef LANG_HOOKS_MISSING_NORETURN_OK_P
 #define LANG_HOOKS_MISSING_NORETURN_OK_P cp_missing_noreturn_ok_p
 
+/* There are still some bugs to be worked out with C++ scoping and lazy
+   builtins, so for now disable lazy builtins by default.  */
+#undef	LANG_HOOKS_LAZY_BUILTIN_P
+#define	LANG_HOOKS_LAZY_BUILTIN_P false /* true */
+
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
 #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(.../trunk)	(revision 180408)
+++ gcc/cp/name-lookup.c	(.../branches/ibm/builtin)	(revision 180409)
@@ -4518,6 +4518,18 @@  lookup_name_real_1 (tree name, int prefe
   cxx_binding *iter;
   tree val = NULL_TREE;
 
+  /* If this identifier is a lazy builtin whose function type has not yet been
+     created, create it now before doing the lookup.  */
+  if (IDENTIFIER_LAZY_BUILTIN_P (name))
+    {
+      if (flag_lazy_builtin_debug)
+	fprintf (stderr, "---lookup_name_read_1 (%s)\n",
+		 IDENTIFIER_POINTER (name));
+
+      (void) builtin_lazy_create (name);
+    }
+
+
   /* Conversion operators are handled specially because ordinary
      unqualified name lookup will not find template conversion
      operators.  */
Index: gcc/c-objc-common.h
===================================================================
--- gcc/c-objc-common.h	(.../trunk)	(revision 180408)
+++ gcc/c-objc-common.h	(.../branches/ibm/builtin)	(revision 180409)
@@ -61,6 +61,12 @@  along with GCC; see the file COPYING3.  
 #define LANG_HOOKS_BUILTIN_FUNCTION c_builtin_function
 #undef  LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE
 #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE c_builtin_function_ext_scope
+#undef	LANG_HOOKS_BUILTIN_LAZY_REGISTER
+#define	LANG_HOOKS_BUILTIN_LAZY_REGISTER c_common_builtin_lazy_register
+#undef	LANG_HOOKS_BUILTIN_LAZY_CREATE
+#define	LANG_HOOKS_BUILTIN_LAZY_CREATE c_common_builtin_lazy_create
+#undef	LANG_HOOKS_LAZY_BUILTIN_P
+#define	LANG_HOOKS_LAZY_BUILTIN_P true
 
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(.../trunk)	(revision 180408)
+++ gcc/c-decl.c	(.../branches/ibm/builtin)	(revision 180409)
@@ -3459,7 +3459,19 @@  pending_xref_error (void)
 tree
 lookup_name (tree name)
 {
-  struct c_binding *b = I_SYMBOL_BINDING (name);
+  struct c_binding *b;
+
+  /* If this identifier is a lazy builtin whose function type has not yet been
+     created, create it now before doing the lookup.  */
+  if (IDENTIFIER_LAZY_BUILTIN_P (name))
+    {
+      if (flag_lazy_builtin_debug)
+	fprintf (stderr, "---lookup_name (%s)\n", IDENTIFIER_POINTER (name));
+
+      (void) builtin_lazy_create (name);
+    }
+
+  b = I_SYMBOL_BINDING (name);
   if (b && !b->invisible)
     {
       maybe_record_typedef_use (b->decl);
@@ -3475,6 +3487,17 @@  lookup_name_in_scope (tree name, struct 
 {
   struct c_binding *b;
 
+  /* If this identifier is a lazy builtin whose function type has not yet been
+     created, create it now before doing the lookup.  */
+  if (IDENTIFIER_LAZY_BUILTIN_P (name))
+    {
+      if (flag_lazy_builtin_debug)
+	fprintf (stderr, "---lookup_name_in_scope (%s)\n",
+		 IDENTIFIER_POINTER (name));
+
+      (void) builtin_lazy_create (name);
+    }
+
   for (b = I_SYMBOL_BINDING (name); b; b = b->shadowed)
     if (B_IN_SCOPE (b, scope))
       return b->decl;
@@ -3588,11 +3611,25 @@  c_builtin_function (tree decl)
   const char *name = IDENTIFIER_POINTER (id);
   C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type);
 
+  if (flag_lazy_builtin_debug && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+    fprintf (stderr,
+	     "---c_builtin_function (%s, decl=%p, %s, fncode=%d [%s], "
+	     "implicit=%s, proto=%s)\n",
+	     IDENTIFIER_POINTER (id),
+	     (void *)decl,
+	     built_in_class_names[(int) DECL_BUILT_IN_CLASS (decl)],
+	     (int)DECL_FUNCTION_CODE (decl),
+	     ((DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+	      ? built_in_names[(int)DECL_FUNCTION_CODE (decl)]
+	      : "---"),
+	     C_DECL_IMPLICIT (decl) ? "true" : "false",
+	     C_DECL_BUILTIN_PROTOTYPE (decl) ? "true" : "false");
+
   /* Should never be called on a symbol with a preexisting meaning.  */
   gcc_assert (!I_SYMBOL_BINDING (id));
 
   bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false,
-	UNKNOWN_LOCATION);
+	BUILTINS_LOCATION);
 
   /* Builtins in the implementation namespace are made visible without
      needing to be explicitly declared.  See push_file_scope.  */
@@ -3614,18 +3651,38 @@  c_builtin_function_ext_scope (tree decl)
   const char *name = IDENTIFIER_POINTER (id);
   C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type);
 
-  /* Should never be called on a symbol with a preexisting meaning.  */
-  gcc_assert (!I_SYMBOL_BINDING (id));
-
-  bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false,
-	UNKNOWN_LOCATION);
-
-  /* Builtins in the implementation namespace are made visible without
-     needing to be explicitly declared.  See push_file_scope.  */
-  if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
-    {
-      DECL_CHAIN (decl) = visible_builtins;
-      visible_builtins = decl;
+  if (flag_lazy_builtin_debug)
+    fprintf (stderr,
+	     "---c_builtin_function_ext_scope (%s, decl=%p, %s, "
+	     "fncode=%d [%s], implicit=%s, proto=%s%s%s)\n",
+	     IDENTIFIER_POINTER (id),
+	     (void *)decl,
+	     built_in_class_names[(int) DECL_BUILT_IN_CLASS (decl)],
+	     (int)DECL_FUNCTION_CODE (decl),
+	     ((DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+	      ? built_in_names[(int)DECL_FUNCTION_CODE (decl)]
+	      : "---"),
+	     C_DECL_IMPLICIT (decl) ? "true" : "false",
+	     C_DECL_BUILTIN_PROTOTYPE (decl) ? "true" : "false",
+	     external_scope ? "" : ", no external scope",
+	     I_SYMBOL_BINDING (id) ? ", previous binding" : "");
+
+  /* We might be called after the front end has finished by the backend wanting
+     to create builtin functions.  If so, don't bother adding the declaration
+     to the external scope.  Also, we should not have a binding at this point,
+     but if we do, don't try to bind it again.  */
+  if (external_scope && !I_SYMBOL_BINDING (id))
+    {
+      bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false,
+	    BUILTINS_LOCATION);
+
+      /* Builtins in the implementation namespace are made visible without
+	 needing to be explicitly declared.  See push_file_scope.  */
+      if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
+	{
+	  DECL_CHAIN (decl) = visible_builtins;
+	  visible_builtins = decl;
+	}
     }
 
   return decl;
@@ -4955,6 +5012,17 @@  grokdeclarator (const struct c_declarato
       }
   }
 
+  /* If this identifier is a lazy builtin whose function type has not yet been
+     created, create it now before doing the lookup.  */
+  if (name && IDENTIFIER_LAZY_BUILTIN_P (name))
+    {
+      if (flag_lazy_builtin_debug)
+	fprintf (stderr, "---grokdeclarator (%s)\n",
+		 IDENTIFIER_POINTER (name));
+
+      (void) builtin_lazy_create (name);
+    }
+
   /* A function definition's declarator must have the form of
      a function declarator.  */
 
Index: gcc/langhooks.c
===================================================================
--- gcc/langhooks.c	(.../trunk)	(revision 180408)
+++ gcc/langhooks.c	(.../branches/ibm/builtin)	(revision 180409)
@@ -524,8 +524,7 @@  lhd_omp_firstprivatize_type_sizes (struc
 {
 }
 
-/* Common function for add_builtin_function and
-   add_builtin_function_ext_scope.  */
+/* Set up a builtin function without adding it to the front end's binding.  */
 static tree
 add_builtin_function_common (const char *name,
 			     tree type,
@@ -579,11 +578,9 @@  add_builtin_function (const char *name,
 }
 
 /* Like add_builtin_function, but make sure the scope is the external scope.
-   This is used to delay putting in back end builtin functions until the ISA
-   that defines the builtin is declared via function specific target options,
-   which can save memory for machines like the x86_64 that have multiple ISAs.
-   If this points to the same function as builtin_function, the backend must
-   add all of the builtins at program initialization time.  */
+   This is used for lazy builtin functions that are created when the identifier
+   is frist used.  Some front ends might use the same target hook for this and
+   builtin_function.  */
 
 tree
 add_builtin_function_ext_scope (const char *name,
@@ -657,3 +654,57 @@  lhd_end_section (void)
       saved_section = NULL;
     }
 }
+
+/* Register an identifier that is a lazy builtin that will be expanded by
+   calling the builtin_lazy_create builtin.  If the front does not support lazy
+   builtins, only MD builtins are supported, and they are expanded immediately.
+   When the front end or back end hook is called, it is expected that all
+   varients of the builtin function will be created.  */
+
+tree
+lhd_builtin_lazy_register (const char *name ATTRIBUTE_UNUSED,
+			   unsigned fncode,
+			   enum built_in_class cl)
+{
+  if (flag_lazy_builtin_debug)
+    fprintf (stderr, "---lhd_builtin_lazy_register (%s, %s, %u [%s])\n",
+	     name, built_in_class_names[(int)cl], fncode,
+	     (cl == BUILT_IN_NORMAL) ? built_in_names[fncode] : "---");
+
+  gcc_assert (cl == BUILT_IN_MD);
+  return targetm.builtin_decl (fncode, true);
+}
+
+/* Call the language or backend hook to create lazy builtin with identifier
+   IDENT, and add it to the front end's symbol table.  */
+
+tree
+builtin_lazy_create (tree ident)
+{
+  unsigned fncode = builtin_lazy_function_code (ident);
+  enum built_in_class cl = builtin_lazy_function_class (ident);
+
+  if (flag_lazy_builtin_debug)
+    fprintf (stderr, "---builtin_lazy_create (%s, %s, %u [%s]\n",
+	     IDENTIFIER_POINTER (ident),
+	     built_in_class_names[ (int)cl ],
+	     fncode,
+	     (cl == BUILT_IN_NORMAL) ? built_in_names[fncode] : "---");
+
+  if (cl == BUILT_IN_NORMAL || cl == BUILT_IN_FRONTEND)
+    return lang_hooks.builtin_lazy_create (ident, fncode, cl);
+
+  else if (cl == BUILT_IN_MD)
+    return targetm.builtin_decl (fncode, true);
+
+  else
+    gcc_unreachable ();
+}
+
+tree
+lhd_builtin_lazy_create (tree ident ATTRIBUTE_UNUSED,
+			 unsigned fncode ATTRIBUTE_UNUSED,
+			 enum built_in_class cl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
Index: gcc/langhooks.h
===================================================================
--- gcc/langhooks.h	(.../trunk)	(revision 180408)
+++ gcc/langhooks.h	(.../branches/ibm/builtin)	(revision 180409)
@@ -249,6 +249,17 @@  struct lang_hooks_for_lto
   void (*end_section) (void);
 };
 
+/* Each front end provides its own.  */
+extern struct lang_hooks lang_hooks;
+typedef tree add_builtin_function_type (const char *name, tree type,
+					int function_code,
+					enum built_in_class cl,
+					const char *library_name,
+					tree attrs);
+
+extern add_builtin_function_type add_builtin_function;
+extern add_builtin_function_type add_builtin_function_ext_scope;
+
 /* Language-specific hooks.  See langhooks-def.h for defaults.  */
 
 struct lang_hooks
@@ -436,13 +447,25 @@  struct lang_hooks
   tree (*builtin_function) (tree decl);
 
   /* Like builtin_function, but make sure the scope is the external scope.
-     This is used to delay putting in back end builtin functions until the ISA
-     that defines the builtin is declared via function specific target options,
-     which can save memory for machines like the x86_64 that have multiple
-     ISAs.  If this points to the same function as builtin_function, the
-     backend must add all of the builtins at program initialization time.  */
+     This is used for lazy builtin functions that are created when the
+     identifier is frist used.  Some front ends might use the same target hook
+     for this and builtin_function.  */
   tree (*builtin_function_ext_scope) (tree decl);
 
+  /* Register an identifier that is a lazy builtin that will be expanded by
+     calling the builtin_lazy_create builtin.  If the front does not support
+     lazy builtins, only MD builtins are supported, and they are expanded
+     immediately.  When the front end or back end hook is called, it is
+     expected that all varients of the builtin function will be created.
+     Return the IDENTIFIER_NODE of the function if it is lazy or the
+     declaration node if it was created immediately.  */
+  tree (*builtin_lazy_register) (const char *name, unsigned fncode,
+				 enum built_in_class cl);
+
+  /* Call the language hook to create a standard or front end lazy builtin with
+     identifier IDENT.  Machine builtins are handled via the targetm hook.  */
+  tree (*builtin_lazy_create) (tree ident, unsigned, enum built_in_class);
+
   /* Used to set up the tree_contains_structure array for a frontend. */
   void (*init_ts) (void);
 
@@ -473,21 +496,11 @@  struct lang_hooks
      gimplification.  */
   bool deep_unsharing;
 
+  /* True if this language should enable lazy builtins by default.  */
+  bool lazy_builtin_p;
+
   /* Whenever you add entries here, make sure you adjust langhooks-def.h
      and langhooks.c accordingly.  */
 };
 
-/* Each front end provides its own.  */
-extern struct lang_hooks lang_hooks;
-extern tree add_builtin_function (const char *name, tree type,
-				  int function_code, enum built_in_class cl,
-				  const char *library_name,
-				  tree attrs);
-
-extern tree add_builtin_function_ext_scope (const char *name, tree type,
-					    int function_code,
-					    enum built_in_class cl,
-					    const char *library_name,
-					    tree attrs);
-
 #endif /* GCC_LANG_HOOKS_H */
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(.../trunk)	(revision 180408)
+++ gcc/common.opt	(.../branches/ibm/builtin)	(revision 180409)
@@ -1174,6 +1174,14 @@  fgraphite-identity
 Common Report Var(flag_graphite_identity) Optimization
 Enable Graphite Identity transformation
 
+flazy-builtin
+Common Report Var(flag_lazy_builtin) Optimization Init(-1)
+Don't create builtin nodes at compiler startup.
+
+flazy-builtin-debug
+Common Undocumented Var(flag_lazy_builtin_debug) Optimization
+; Turn on lazy builtins debugging
+
 floop-parallelize-all
 Common Report Var(flag_loop_parallelize_all) Optimization
 Mark all loops as parallel
Index: gcc/langhooks-def.h
===================================================================
--- gcc/langhooks-def.h	(.../trunk)	(revision 180408)
+++ gcc/langhooks-def.h	(.../branches/ibm/builtin)	(revision 180409)
@@ -70,7 +70,9 @@  extern bool lhd_complain_wrong_lang_p (c
 extern bool lhd_handle_option (size_t, const char *, int, int, location_t,
 			       const struct cl_option_handlers *);
 extern tree lhd_callgraph_analyze_expr (tree *, int *);
-
+extern tree lhd_builtin_lazy_register (const char *, unsigned,
+				       enum built_in_class);
+extern tree lhd_builtin_lazy_create (tree, unsigned, enum built_in_class);
 
 /* Declarations for tree gimplification hooks.  */
 extern int lhd_gimplify_expr (tree *, gimple_seq *, gimple_seq *);
@@ -110,6 +112,8 @@  extern void lhd_omp_firstprivatize_type_
 #define LANG_HOOKS_TYPES_COMPATIBLE_P	lhd_types_compatible_p
 #define LANG_HOOKS_BUILTIN_FUNCTION	lhd_builtin_function
 #define LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE	LANG_HOOKS_BUILTIN_FUNCTION
+#define LANG_HOOKS_BUILTIN_LAZY_REGISTER lhd_builtin_lazy_register
+#define LANG_HOOKS_BUILTIN_LAZY_CREATE	lhd_builtin_lazy_create
 #define LANG_HOOKS_EXPR_TO_DECL		lhd_expr_to_decl
 #define LANG_HOOKS_TO_TARGET_CHARSET	lhd_to_target_charset
 #define LANG_HOOKS_INIT_TS		lhd_do_nothing
@@ -118,6 +122,7 @@  extern void lhd_omp_firstprivatize_type_
 #define LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS	NULL
 #define LANG_HOOKS_EH_USE_CXA_END_CLEANUP	false
 #define LANG_HOOKS_DEEP_UNSHARING	false
+#define LANG_HOOKS_LAZY_BUILTIN_P	false
 
 /* Attribute hooks.  */
 #define LANG_HOOKS_ATTRIBUTE_TABLE		NULL
@@ -303,13 +308,16 @@  extern void lhd_end_section (void);
   LANG_HOOKS_GIMPLIFY_EXPR, \
   LANG_HOOKS_BUILTIN_FUNCTION, \
   LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE, \
+  LANG_HOOKS_BUILTIN_LAZY_REGISTER, \
+  LANG_HOOKS_BUILTIN_LAZY_CREATE, \
   LANG_HOOKS_INIT_TS,          \
   LANG_HOOKS_EXPR_TO_DECL, \
   LANG_HOOKS_EH_PERSONALITY, \
   LANG_HOOKS_EH_RUNTIME_TYPE, \
   LANG_HOOKS_EH_PROTECT_CLEANUP_ACTIONS, \
   LANG_HOOKS_EH_USE_CXA_END_CLEANUP, \
-  LANG_HOOKS_DEEP_UNSHARING \
+  LANG_HOOKS_DEEP_UNSHARING, \
+  LANG_HOOKS_LAZY_BUILTIN_P \
 }
 
 #endif /* GCC_LANG_HOOKS_DEF_H */