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 <meiss...@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 <meiss...@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 <meiss...@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. -- Michael Meissner, IBM 5 Technology Place Drive, M/S 2757, Westford, MA 01886-3141, USA meiss...@linux.vnet.ibm.com fax +1 (978) 399-6899
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 */
#include <stddef.h> extern "C++" { extern char *strrchr (char *__s, int __c) throw () __asm ("strrchr") __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1))); extern __const char *strrchr (__const char *__s, int __c) throw () __asm ("strrchr") __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1))); extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__, __artificial__)) char * strrchr (char *__s, int __c) throw () { return __builtin_strrchr (__s, __c); } extern __inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__, __artificial__)) __const char * strrchr (__const char *__s, int __c) throw () { return __builtin_strrchr (__s, __c); } } extern "C" { extern size_t strlen (__const char *__s) throw () __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1))); extern char *strcpy (char *__restrict __dest, __const char *__restrict __src) throw () __attribute__ ((__nonnull__ (1, 2))); } extern void use_ptr (char *); void foo (const char *start) { char *o = (char *) __builtin_alloca(strlen (start) + strlen (".o") + 1); char *suffix; strcpy (o, start); suffix = strrchr (o, '.'); if (!suffix) suffix = o + strlen (o); strcpy (suffix, ".o"); use_ptr (o); } // HISTORY // $Log: test-builtin-overload.cc,v $ // Revision 1.2 2011-10-24 18:05:07 michaelmeissner // Use stddef.h for size_t, instead of assuming long unsigned // // Revision 1.1 2011-10-24 18:00:57 michaelmeissner // Initial version. //