diff mbox series

Ping: Add a simulate_builin_function_decl langhook

Message ID mptpnizxizt.fsf@arm.com
State New
Headers show
Series Ping: Add a simulate_builin_function_decl langhook | expand

Commit Message

Richard Sandiford Oct. 14, 2019, 6:46 p.m. UTC
Ping

See also https://gcc.gnu.org/ml/gcc-patches/2019-10/msg00413.html
for more details about why this seemed like a good idea.  A shorter
version of that message (well, it started out that way :-)) is that
it lets us use:

  #ifndef _ARM_SVE_H_
  #define _ARM_SVE_H_

  #include <stdint.h>

  typedef __fp16 float16_t;
  typedef float float32_t;
  typedef double float64_t;

  #pragma GCC aarch64 "arm_sve.h"

  #endif

as the full intrinsics header file.  Rather than have GCC call:

  add_builtin_function ("__builtin_aarch64_svarsd_s16_n_x",
                        fntype, code, BUILT_IN_MD, NULL, attrs);

at start-up and having the header file provide an inline wrapper like:

  __extension__ extern __inline svint8_t
  __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
  svasrd_n_s16_x (svbool_t __a, svint8_t __b, int64_t __c)
  {
    return __builtin_aarch64_svasrd_n_s16_x (__a, __b, __c);
  }

we can just have GCC call:

  simulate_builtin_function_decl (input_location, "svasrd_n_s16_x",
                                  fntype, code, NULL, attrs);

when the header pragma is invoked.

When repeated for thousands of functions, this significantly reduces
the amount of code needed.  It also gives quicker start-up times
(because functions are only registered when they're needed) and makes
arm_sve.h compile more quickly (because there's less code to parse).

Another benefit is that inline wrappers don't show up in error messages.
E.g.:

  #include <arm_neon.h>
  int8x8_t foo (int16x8_t x, int y)
  { return vqrshrn_n_s16 (x, y); }

gives:

  In file included from foo.c:3:10:
  In function 'vqrshrn_n_s16',
      inlined from 'foo' at foo.c:2:
  include/arm_neon.h:24419:10: error: argument 2 must be a constant immediate
  24419 |   return (int8x8_t) __builtin_aarch64_sqrshrn_nv8hi (__a, __b);
        |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

where the quoted line is the inline wrapper in arm_neon.h rather than
the user's code.  An SVE example like:

  #include <arm_sve.h>
  svint16_t foo (svbool_t pg, svint16_t x, int y)
  { return svasrd_x (pg, x, y); }

instead gives:

  foo.c: In function 'foo':
  foo.c:3:10: error: argument 3 of 'svasrd_x' must be an integer constant expression
      3 | { return svasrd_x (pg, x, y); }
        |          ^~~~~~~~

which seems more user-friendly.

Thanks,
Richard

Richard Sandiford <richard.sandiford@arm.com> writes:
> 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.sandiford@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.

Comments

Richard Sandiford Oct. 18, 2019, 1:59 p.m. UTC | #1
Here's a version rebased on top of Nathan's C++ patch yesterday.
This actually makes the patch simpler; the changes to the frontends
are now pure additions, so no existing frontend code should be affected.

FWIW, this patch and the enum one:

  https://gcc.gnu.org/ml/gcc-patches/2019-09/msg01523.html
  pinged with more rationale here:
  https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01003.html

are the only remaining prerequisites we need before adding (fixed-length
support for) the SVE intrinsics and calling conventions.

Thanks,
Richard

Richard Sandiford <richard.sandiford@arm.com> writes:
> Ping
>
> See also https://gcc.gnu.org/ml/gcc-patches/2019-10/msg00413.html
> for more details about why this seemed like a good idea.  A shorter
> version of that message (well, it started out that way :-)) is that
> it lets us use:
>
>   #ifndef _ARM_SVE_H_
>   #define _ARM_SVE_H_
>
>   #include <stdint.h>
>
>   typedef __fp16 float16_t;
>   typedef float float32_t;
>   typedef double float64_t;
>
>   #pragma GCC aarch64 "arm_sve.h"
>
>   #endif
>
> as the full intrinsics header file.  Rather than have GCC call:
>
>   add_builtin_function ("__builtin_aarch64_svarsd_s16_n_x",
>                         fntype, code, BUILT_IN_MD, NULL, attrs);
>
> at start-up and having the header file provide an inline wrapper like:
>
>   __extension__ extern __inline svint8_t
>   __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
>   svasrd_n_s16_x (svbool_t __a, svint8_t __b, int64_t __c)
>   {
>     return __builtin_aarch64_svasrd_n_s16_x (__a, __b, __c);
>   }
>
> we can just have GCC call:
>
>   simulate_builtin_function_decl (input_location, "svasrd_n_s16_x",
>                                   fntype, code, NULL, attrs);
>
> when the header pragma is invoked.
>
> When repeated for thousands of functions, this significantly reduces
> the amount of code needed.  It also gives quicker start-up times
> (because functions are only registered when they're needed) and makes
> arm_sve.h compile more quickly (because there's less code to parse).
>
> Another benefit is that inline wrappers don't show up in error messages.
> E.g.:
>
>   #include <arm_neon.h>
>   int8x8_t foo (int16x8_t x, int y)
>   { return vqrshrn_n_s16 (x, y); }
>
> gives:
>
>   In file included from foo.c:3:10:
>   In function 'vqrshrn_n_s16',
>       inlined from 'foo' at foo.c:2:
>   include/arm_neon.h:24419:10: error: argument 2 must be a constant immediate
>   24419 |   return (int8x8_t) __builtin_aarch64_sqrshrn_nv8hi (__a, __b);
>         |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> where the quoted line is the inline wrapper in arm_neon.h rather than
> the user's code.  An SVE example like:
>
>   #include <arm_sve.h>
>   svint16_t foo (svbool_t pg, svint16_t x, int y)
>   { return svasrd_x (pg, x, y); }
>
> instead gives:
>
>   foo.c: In function 'foo':
>   foo.c:3:10: error: argument 3 of 'svasrd_x' must be an integer constant expression
>       3 | { return svasrd_x (pg, x, y); }
>         |          ^~~~~~~~
>
> which seems more user-friendly.
>
> Thanks,
> Richard
>
> Richard Sandiford <richard.sandiford@arm.com> writes:
>> 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-10-18  Richard Sandiford  <richard.sandiford@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 (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-10-11 15:43:54.539490518 +0100
+++ gcc/langhooks.h	2019-10-18 14:47:55.430293447 +0100
@@ -504,6 +504,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);
 
@@ -572,6 +581,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-10-11 15:43:55.439484181 +0100
+++ gcc/langhooks-def.h	2019-10-18 14:47:55.430293447 +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
@@ -342,6 +343,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-09-30 17:18:55.000000000 +0100
+++ gcc/langhooks.c	2019-10-18 14:47:55.430293447 +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-09-30 17:18:55.000000000 +0100
+++ gcc/c/c-tree.h	2019-10-18 14:47:55.426293475 +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-10-14 09:04:54.671258198 +0100
+++ gcc/c/c-decl.c	2019-10-18 14:47:55.426293475 +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-09-30 17:18:55.000000000 +0100
+++ gcc/c/c-objc-common.h	2019-10-18 14:47:55.426293475 +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-10-11 15:43:51.783509925 +0100
+++ gcc/cp/cp-tree.h	2019-10-18 14:47:55.426293475 +0100
@@ -6473,6 +6473,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-10-17 14:22:55.351310233 +0100
+++ gcc/cp/decl.c	2019-10-18 14:47:55.430293447 +0100
@@ -4691,6 +4691,19 @@ cxx_builtin_function_ext_scope (tree dec
   return decl;
 }
 
+/* Implement LANG_HOOKS_SIMULATE_BUILTIN_FUNCTION_DECL.  */
+
+tree
+cxx_simulate_builtin_function_decl (tree decl)
+{
+  retrofit_lang_decl (decl);
+
+  DECL_ARTIFICIAL (decl) = 1;
+  SET_DECL_LANGUAGE (decl, lang_cplusplus);
+  DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
+  return pushdecl (decl);
+}
+
 /* 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-09-30 17:18:55.000000000 +0100
+++ gcc/cp/cp-objcp-common.h	2019-10-18 14:47:55.426293475 +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
diff mbox series

Patch

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