Although it's possible to define the SVE intrinsics in a normal header file, it's much more convenient to define them directly in the compiler. This also speeds up compilation and gives better error messages.
The idea is therefore for arm_sve.h (the main intrinsics header file) to have the pragma: #pragma GCC aarch64 "arm_sve.h" telling GCC to define (almost) everything arm_sve.h needs to define. The target then needs a way of injecting new built-in function declarations during compilation. The main hook for defining built-in functions is add_builtin_function. This is designed for use at start-up, and so has various features that are correct in that context but not for the pragma above: (1) the location is always BUILTINS_LOCATION, whereas for arm_sve.h it ought to be the location of the pragma. (2) the function is only immediately visible if it's in the implementation namespace, whereas the pragma is deliberately injecting functions into the general namespace. (3) there's no attempt to emulate a normal function declaration in C or C++, whereas functions declared by the pragma should be checked in the same way as an open-coded declaration would be. E.g. we should get an error if there was a previous incompatible declaration. (4) in C++, the function is treated as extern "C" and so can't be overloaded, whereas SVE intrinsics do use function overloading. This patch therefore adds a hook that targets can use to inject the equivalent of a source-level function declaration, but bound to a BUILT_IN_MD function. The main SVE intrinsic patch has tests to make sure that we report an error for conflicting definitions that appear either before or after including arm_sve.h. Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install? Richard 2019-09-26 Richard Sandiford <richard.sandif...@arm.com> gcc/ * langhooks.h (lang_hooks::simulate_builtin_function_decl): New hook. (simulate_builtin_function_decl): Declare. * langhooks-def.h (LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL): Define. (LANG_HOOKS_INITIALIZER): Include it. * langhooks.c (add_builtin_function_common): Rename to... (build_builtin_function): ...this. Add a location parameter and use it instead of BUILTINS_LOCATION. Remove the hook parameter and return the decl instead. (add_builtin_function): Update accordingly, passing the returned decl to the lang hook. (add_builtin_function_ext_scope): Likewise (simulate_builtin_function_decl): New function. gcc/c/ * c-tree.h (c_simulate_builtin_function_decl): Declare. * c-decl.c (c_simulate_builtin_function_decl): New function. * c-objc-common.h (LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL): Define to the above. gcc/cp/ * cp-tree.h (cxx_simulate_builtin_function_decl): Declare. * decl.c (builtin_function_1): Add an is_simulated_source_decl parameter. When true, treat the function as a C++ function rather than as extern "C", and don't treat it as anticipated. (cxx_simulate_builtin_function_decl): New function. * cp-objcp-common.h (LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL): Define to the above. Index: gcc/langhooks.h =================================================================== --- gcc/langhooks.h 2019-03-08 18:15:33.660751905 +0000 +++ gcc/langhooks.h 2019-09-26 13:02:42.543520465 +0100 @@ -494,6 +494,15 @@ struct lang_hooks backend must add all of the builtins at program initialization time. */ tree (*builtin_function_ext_scope) (tree decl); + /* Do language-specific processing for target-specific built-in + function DECL, so that it is defined in the global scope (only) + and is available without needing to be explicitly declared. + + This is intended for targets that want to inject declarations of + built-in functions into the source language (such as in response + to a pragma) rather than providing them in the source language itself. */ + tree (*simulate_builtin_function_decl) (tree decl); + /* Used to set up the tree_contains_structure array for a frontend. */ void (*init_ts) (void); @@ -562,6 +571,8 @@ extern tree add_builtin_function_ext_sco enum built_in_class cl, const char *library_name, tree attrs); +extern tree simulate_builtin_function_decl (location_t, const char *, tree, + int, const char *, tree); extern tree add_builtin_type (const char *name, tree type); /* Language helper functions. */ Index: gcc/langhooks-def.h =================================================================== --- gcc/langhooks-def.h 2019-03-08 18:15:39.328730361 +0000 +++ gcc/langhooks-def.h 2019-09-26 13:02:42.543520465 +0100 @@ -122,6 +122,7 @@ #define LANG_HOOKS_TREE_SIZE lhd_tree_s #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_SIMULATE_BUILTIN_FUNCTION_DECL LANG_HOOKS_BUILTIN_FUNCTION #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 @@ -338,6 +339,7 @@ #define LANG_HOOKS_INITIALIZER { \ LANG_HOOKS_GIMPLIFY_EXPR, \ LANG_HOOKS_BUILTIN_FUNCTION, \ LANG_HOOKS_BUILTIN_FUNCTION_EXT_SCOPE, \ + LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL, \ LANG_HOOKS_INIT_TS, \ LANG_HOOKS_EXPR_TO_DECL, \ LANG_HOOKS_EH_PERSONALITY, \ Index: gcc/langhooks.c =================================================================== --- gcc/langhooks.c 2019-08-25 19:10:35.194159619 +0100 +++ gcc/langhooks.c 2019-09-26 13:02:42.543520465 +0100 @@ -599,19 +599,16 @@ lhd_omp_mappable_type (tree type) return true; } -/* Common function for add_builtin_function and - add_builtin_function_ext_scope. */ +/* Common function for add_builtin_function, add_builtin_function_ext_scope + and simulate_builtin_function_decl. */ + static tree -add_builtin_function_common (const char *name, - tree type, - int function_code, - enum built_in_class cl, - const char *library_name, - tree attrs, - tree (*hook) (tree)) +build_builtin_function (location_t location, const char *name, tree type, + int function_code, enum built_in_class cl, + const char *library_name, tree attrs) { tree id = get_identifier (name); - tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, id, type); + tree decl = build_decl (location, FUNCTION_DECL, id, type); TREE_PUBLIC (decl) = 1; DECL_EXTERNAL (decl) = 1; @@ -632,8 +629,7 @@ add_builtin_function_common (const char else decl_attributes (&decl, NULL_TREE, 0); - return hook (decl); - + return decl; } /* Create a builtin function. */ @@ -646,9 +642,9 @@ add_builtin_function (const char *name, const char *library_name, tree attrs) { - return add_builtin_function_common (name, type, function_code, cl, - library_name, attrs, - lang_hooks.builtin_function); + tree decl = build_builtin_function (BUILTINS_LOCATION, name, type, + function_code, cl, library_name, attrs); + return lang_hooks.builtin_function (decl); } /* Like add_builtin_function, but make sure the scope is the external scope. @@ -666,9 +662,40 @@ add_builtin_function_ext_scope (const ch const char *library_name, tree attrs) { - return add_builtin_function_common (name, type, function_code, cl, - library_name, attrs, - lang_hooks.builtin_function_ext_scope); + tree decl = build_builtin_function (BUILTINS_LOCATION, name, type, + function_code, cl, library_name, attrs); + return lang_hooks.builtin_function_ext_scope (decl); +} + +/* Simulate a declaration of a target-specific built-in function at + location LOCATION, as though it had been declared directly in the + source language. NAME is the name of the function, TYPE is its function + type, FUNCTION_CODE is the target-specific function code, LIBRARY_NAME + is the name of the underlying library function (NULL if none) and + ATTRS is a list of function attributes. + + Return the decl of the declared function. */ + +tree +simulate_builtin_function_decl (location_t location, const char *name, + tree type, int function_code, + const char *library_name, tree attrs) +{ + tree decl = build_builtin_function (location, name, type, + function_code, BUILT_IN_MD, + library_name, attrs); + tree new_decl = lang_hooks.simulate_builtin_function_decl (decl); + + /* Give the front end a chance to create a new decl if necessary, + but if the front end discards the decl in favour of a conflicting + (erroneous) previous definition, return the decl that we tried but + failed to add. This allows the caller to process the returned decl + normally, even though the source code won't be able to use it. */ + if (TREE_CODE (new_decl) == FUNCTION_DECL + && fndecl_built_in_p (new_decl, function_code, BUILT_IN_MD)) + return new_decl; + + return decl; } tree Index: gcc/c/c-tree.h =================================================================== --- gcc/c/c-tree.h 2019-07-10 19:41:20.543944894 +0100 +++ gcc/c/c-tree.h 2019-09-26 13:02:42.539520492 +0100 @@ -579,6 +579,7 @@ extern struct c_declarator *set_array_de struct c_declarator *); extern tree c_builtin_function (tree); extern tree c_builtin_function_ext_scope (tree); +extern tree c_simulate_builtin_function_decl (tree); extern void shadow_tag (const struct c_declspecs *); extern void shadow_tag_warned (const struct c_declspecs *, int); extern tree start_enum (location_t, struct c_enum_contents *, tree); Index: gcc/c/c-decl.c =================================================================== --- gcc/c/c-decl.c 2019-09-21 13:56:06.983948786 +0100 +++ gcc/c/c-decl.c 2019-09-26 13:02:42.539520492 +0100 @@ -4481,6 +4481,16 @@ c_builtin_function_ext_scope (tree decl) return decl; } + +/* Implement LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL. */ + +tree +c_simulate_builtin_function_decl (tree decl) +{ + tree type = TREE_TYPE (decl); + C_DECL_BUILTIN_PROTOTYPE (decl) = prototype_p (type); + return pushdecl (decl); +} /* Called when a declaration is seen that contains no names to declare. If its type is a reference to a structure, union or enum inherited Index: gcc/c/c-objc-common.h =================================================================== --- gcc/c/c-objc-common.h 2019-04-04 08:34:51.661939350 +0100 +++ gcc/c/c-objc-common.h 2019-09-26 13:02:42.539520492 +0100 @@ -60,6 +60,9 @@ #define LANG_HOOKS_MISSING_NORETURN_OK_P #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_SIMULATE_BUILTIN_FUNCTION_DECL +#define LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL \ + c_simulate_builtin_function_decl #undef LANG_HOOKS_EMITS_BEGIN_STMT #define LANG_HOOKS_EMITS_BEGIN_STMT true Index: gcc/cp/cp-tree.h =================================================================== --- gcc/cp/cp-tree.h 2019-09-26 08:38:00.759713359 +0100 +++ gcc/cp/cp-tree.h 2019-09-26 13:02:42.539520492 +0100 @@ -6461,6 +6461,7 @@ extern tmpl_spec_kind current_tmpl_spec_ extern tree cp_fname_init (const char *, tree *); extern tree cxx_builtin_function (tree decl); extern tree cxx_builtin_function_ext_scope (tree decl); +extern tree cxx_simulate_builtin_function_decl (tree); extern tree check_elaborated_type_specifier (enum tag_types, tree, bool); extern void warn_extern_redeclared_static (tree, tree); extern tree cxx_comdat_group (tree); Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c 2019-09-17 15:27:10.958069743 +0100 +++ gcc/cp/decl.c 2019-09-26 13:02:42.543520465 +0100 @@ -71,7 +71,6 @@ static tree grokvardecl (tree, tree, tre int, int, int, bool, int, tree, location_t); static void check_static_variable_definition (tree, tree); static void record_unknown_type (tree, const char *); -static tree builtin_function_1 (tree, tree, bool); static int member_function_or_else (tree, tree, enum overload_flags); static tree local_variable_p_walkfn (tree *, int *, void *); static const char *tag_name (enum tag_types); @@ -4567,8 +4566,12 @@ cp_make_fname_decl (location_t loc, tree return decl; } +/* IS_SIMULATED_DECL is true if the decl should simulate a global + declaration in the source language. */ + static tree -builtin_function_1 (tree decl, tree context, bool is_global) +builtin_function_1 (tree decl, tree context, bool is_global, + bool is_simulated_decl = false) { tree id = DECL_NAME (decl); const char *name = IDENTIFIER_POINTER (id); @@ -4576,7 +4579,10 @@ builtin_function_1 (tree decl, tree cont retrofit_lang_decl (decl); DECL_ARTIFICIAL (decl) = 1; - SET_DECL_LANGUAGE (decl, lang_c); + if (is_simulated_decl) + SET_DECL_LANGUAGE (decl, lang_cplusplus); + else + SET_DECL_LANGUAGE (decl, lang_c); /* Runtime library routines are, by definition, available in an external shared object. */ DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; @@ -4584,21 +4590,24 @@ builtin_function_1 (tree decl, tree cont DECL_CONTEXT (decl) = context; - /* A function in the user's namespace should have an explicit - declaration before it is used. Mark the built-in function as - anticipated but not actually declared. */ - if (name[0] != '_' || name[1] != '_') - DECL_ANTICIPATED (decl) = 1; - else if (strncmp (name + 2, "builtin_", strlen ("builtin_")) != 0) - { - size_t len = strlen (name); - - /* Treat __*_chk fortification functions as anticipated as well, - unless they are __builtin_*. */ - if (len > strlen ("___chk") - && memcmp (name + len - strlen ("_chk"), - "_chk", strlen ("_chk") + 1) == 0) + if (!is_simulated_decl) + { + /* A function in the user's namespace should have an explicit + declaration before it is used. Mark the built-in function as + anticipated but not actually declared. */ + if (name[0] != '_' || name[1] != '_') DECL_ANTICIPATED (decl) = 1; + else if (strncmp (name + 2, "builtin_", strlen ("builtin_")) != 0) + { + size_t len = strlen (name); + + /* Treat __*_chk fortification functions as anticipated as well, + unless they are __builtin_*. */ + if (len > strlen ("___chk") + && memcmp (name + len - strlen ("_chk"), + "_chk", strlen ("_chk") + 1) == 0) + DECL_ANTICIPATED (decl) = 1; + } } if (is_global) @@ -4650,6 +4659,14 @@ cxx_builtin_function_ext_scope (tree dec return builtin_function_1 (decl, NULL_TREE, true); } +/* Implement LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL. */ + +tree +cxx_simulate_builtin_function_decl (tree decl) +{ + return builtin_function_1 (decl, NULL_TREE, true, true); +} + /* Generate a FUNCTION_DECL with the typical flags for a runtime library function. Not called directly. */ Index: gcc/cp/cp-objcp-common.h =================================================================== --- gcc/cp/cp-objcp-common.h 2019-03-08 18:15:25.000784821 +0000 +++ gcc/cp/cp-objcp-common.h 2019-09-26 13:02:42.539520492 +0100 @@ -100,6 +100,9 @@ #define LANG_HOOKS_POST_COMPILATION_PARS #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_SIMULATE_BUILTIN_FUNCTION_DECL +#define LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL \ + cxx_simulate_builtin_function_decl #undef LANG_HOOKS_TYPE_HASH_EQ #define LANG_HOOKS_TYPE_HASH_EQ cxx_type_hash_eq #undef LANG_HOOKS_COPY_LANG_QUALIFIERS