===================================================================
@@ -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)
===================================================================
@@ -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
===================================================================
@@ -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);
===================================================================
@@ -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 */
===================================================================
@@ -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);
===================================================================
@@ -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
===================================================================
@@ -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. */
===================================================================
@@ -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
===================================================================
@@ -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. */
===================================================================
@@ -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 ();
+}
===================================================================
@@ -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 */
===================================================================
@@ -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
===================================================================
@@ -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 */