[C][C++] Allow targets to check calls to BUILT_IN_MD functions
authorRichard Sandiford <richard.sandiford@arm.com>
Fri, 27 Sep 2019 08:39:16 +0000 (08:39 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Fri, 27 Sep 2019 08:39:16 +0000 (08:39 +0000)
For SVE, we'd like the frontends to check calls to target-specific
built-in functions in the same way that they already do for "normal"
builtins.  This patch adds a target hook for that and extends
check_builtin_function_arguments accordingly.

A slight complication is that when TARGET_RESOLVE_OVERLOADED_BUILTIN
has resolved an overload, it can use build_function_call_vec to build
the call to the underlying non-overloaded function decl.  This in
turn coerces the arguments to the function type and then calls
check_builtin_function_arguments to check the final call.  If the
target does find a problem in this final call, it can be useful
to refer to the original overloaded function decl in diagnostics,
since that's what the user wrote.

The patch therefore passes the original decl as a final optional
parameter to build_function_call_vec.

2019-09-27  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
* target.def (check_builtin_call): New target hook.
* doc/tm.texi.in (TARGET_CHECK_BUILTIN_CALL): New @hook.
* doc/tm.texi: Regenerate.

gcc/c-family/
* c-common.h (build_function_call_vec): Take the original
function decl as an optional final parameter.
(check_builtin_function_arguments): Take the original function decl.
* c-common.c (check_builtin_function_arguments): Likewise.
Handle all built-in functions, not just BUILT_IN_NORMAL ones.
Use targetm.check_builtin_call to check BUILT_IN_MD functions.

gcc/c/
* c-typeck.c (build_function_call_vec): Take the original function
decl as an optional final parameter.  Pass all built-in calls to
check_builtin_function_arguments.

gcc/cp/
* cp-tree.h (build_cxx_call): Take the original function decl
as an optional final parameter.
(cp_build_function_call_vec): Likewise.
* call.c (build_cxx_call): Likewise.  Pass all built-in calls to
check_builtin_function_arguments.
* typeck.c (build_function_call_vec): Take the original function
decl as an optional final parameter and pass it to
cp_build_function_call_vec.
(cp_build_function_call_vec): Take the original function
decl as an optional final parameter and pass it to build_cxx_call.

From-SVN: r276176

13 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/typeck.c
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/target.def

index fe6b333be6f054855ce5d419959b6af0ff7a561a..b6a19c4e2f7e07fc73858aeb1821eac7053cf9b0 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-27  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * target.def (check_builtin_call): New target hook.
+       * doc/tm.texi.in (TARGET_CHECK_BUILTIN_CALL): New @hook.
+       * doc/tm.texi: Regenerate.
+
 2019-09-27  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR tree-optimization/91909
index 93bdf3e07988ec337cb4863143511d83cf0aa97f..7b10957ad02a0b7ee8af2e86be62965bbb944a6d 100644 (file)
@@ -1,3 +1,12 @@
+2019-09-27  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * c-common.h (build_function_call_vec): Take the original
+       function decl as an optional final parameter.
+       (check_builtin_function_arguments): Take the original function decl.
+       * c-common.c (check_builtin_function_arguments): Likewise.
+       Handle all built-in functions, not just BUILT_IN_NORMAL ones.
+       Use targetm.check_builtin_call to check BUILT_IN_MD functions.
+
 2019-09-15  Jason Merrill  <jason@redhat.com>
 
        * c-warn.c (warn_logical_operator): Strip location wrappers.  Don't
index 3756219e5cf6921df320f8eeddf34ecb900b964d..7169813d0f26a1a3621d536748236b4ba8b5d904 100644 (file)
@@ -5856,15 +5856,27 @@ builtin_function_validate_nargs (location_t loc, tree fndecl, int nargs,
 /* Verifies the NARGS arguments ARGS to the builtin function FNDECL.
    Returns false if there was an error, otherwise true.  LOC is the
    location of the function; ARG_LOC is a vector of locations of the
-   arguments.  */
+   arguments.  If FNDECL is the result of resolving an overloaded
+   target built-in, ORIG_FNDECL is the original function decl,
+   otherwise it is null.  */
 
 bool
 check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
-                                 tree fndecl, int nargs, tree *args)
+                                 tree fndecl, tree orig_fndecl,
+                                 int nargs, tree *args)
 {
-  if (!fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
+  if (!fndecl_built_in_p (fndecl))
     return true;
 
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+    return (!targetm.check_builtin_call
+           || targetm.check_builtin_call (loc, arg_loc, fndecl,
+                                          orig_fndecl, nargs, args));
+
+  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
+    return true;
+
+  gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL);
   switch (DECL_FUNCTION_CODE (fndecl))
     {
     case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
index a9f4d0c5c11e38b93db2a985da840c6532879176..c1554f3c3af2083a0bfff4323b14ccb097d1f9f2 100644 (file)
@@ -818,7 +818,7 @@ extern void check_function_arguments_recurse (void (*)
                                              void *, tree,
                                              unsigned HOST_WIDE_INT);
 extern bool check_builtin_function_arguments (location_t, vec<location_t>,
-                                             tree, int, tree *);
+                                             tree, tree, int, tree *);
 extern void check_function_format (const_tree, tree, int, tree *,
                                   vec<location_t> *);
 extern bool attribute_fallthrough_p (tree);
@@ -995,7 +995,8 @@ extern bool c_switch_covers_all_cases_p (splay_tree, tree);
 extern tree build_function_call (location_t, tree, tree);
 
 extern tree build_function_call_vec (location_t, vec<location_t>, tree,
-                                    vec<tree, va_gc> *, vec<tree, va_gc> *);
+                                    vec<tree, va_gc> *, vec<tree, va_gc> *,
+                                    tree = NULL_TREE);
 
 extern tree resolve_overloaded_builtin (location_t, tree, vec<tree, va_gc> *);
 
index 96655493ac008fdf279eec22b34a124a44783cfa..718e5b8b8509ae5fcea958cfd71ebb0c1c0c78ac 100644 (file)
@@ -1,3 +1,9 @@
+2019-09-27  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * c-typeck.c (build_function_call_vec): Take the original function
+       decl as an optional final parameter.  Pass all built-in calls to
+       check_builtin_function_arguments.
+
 2019-09-20  Eric Botcazou  <ebotcazou@adacore.com>
 
        PR c/91815
index d4e12eb93d1d2d774ed4f5964d5434e18d4109ae..cc13fdc84c879df59815c18cedfaef5685e413f4 100644 (file)
@@ -3003,6 +3003,8 @@ inform_declaration (tree decl)
 }
 
 /* Build a function call to function FUNCTION with parameters PARAMS.
+   If FUNCTION is the result of resolving an overloaded target built-in,
+   ORIG_FUNDECL is the original function decl, otherwise it is null.
    ORIGTYPES, if not NULL, is a vector of types; each element is
    either NULL or the original type of the corresponding element in
    PARAMS.  The original type may differ from TREE_TYPE of the
@@ -3013,7 +3015,7 @@ inform_declaration (tree decl)
 tree
 build_function_call_vec (location_t loc, vec<location_t> arg_loc,
                         tree function, vec<tree, va_gc> *params,
-                        vec<tree, va_gc> *origtypes)
+                        vec<tree, va_gc> *origtypes, tree orig_fundecl)
 {
   tree fntype, fundecl = NULL_TREE;
   tree name = NULL_TREE, result;
@@ -3033,6 +3035,8 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
       if (flag_tm)
        tm_malloc_replacement (function);
       fundecl = function;
+      if (!orig_fundecl)
+       orig_fundecl = fundecl;
       /* Atomic functions have type checking/casting already done.  They are 
         often rewritten and don't match the original parameter list.  */
       if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9))
@@ -3110,9 +3114,10 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   argarray = vec_safe_address (params);
 
   /* Check that arguments to builtin functions match the expectations.  */
-  if (fundecl && fndecl_built_in_p (fundecl, BUILT_IN_NORMAL)
-      && !check_builtin_function_arguments (loc, arg_loc, fundecl, nargs,
-                                           argarray))
+  if (fundecl
+      && fndecl_built_in_p (fundecl)
+      && !check_builtin_function_arguments (loc, arg_loc, fundecl,
+                                           orig_fundecl, nargs, argarray))
     return error_mark_node;
 
   /* Check that the arguments to the function are valid.  */
index 1d30cef717e2b7170c2f89bd54546a198e663a38..3a3ef9ed2502016bda5fbb7f23a4c5c3bb931f22 100644 (file)
@@ -1,3 +1,16 @@
+2019-09-27  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * cp-tree.h (build_cxx_call): Take the original function decl
+       as an optional final parameter.
+       (cp_build_function_call_vec): Likewise.
+       * call.c (build_cxx_call): Likewise.  Pass all built-in calls to
+       check_builtin_function_arguments.
+       * typeck.c (build_function_call_vec): Take the original function
+       decl as an optional final parameter and pass it to
+       cp_build_function_call_vec.
+       (cp_build_function_call_vec): Take the original function
+       decl as an optional final parameter and pass it to build_cxx_call.
+
 2019-09-25  Marek Polacek  <polacek@redhat.com>
 
        PR c++/91877 - ICE with converting member of packed struct.
index 45b984ecb1185497361d5a4e424ab0fc7b4f8230..5ccf3b89682c114bcc2fd9773399a18752258556 100644 (file)
@@ -9105,12 +9105,14 @@ maybe_warn_class_memaccess (location_t loc, tree fndecl,
 }
 
 /* Build and return a call to FN, using NARGS arguments in ARGARRAY.
+   If FN is the result of resolving an overloaded target built-in,
+   ORIG_FNDECL is the original function decl, otherwise it is null.
    This function performs no overload resolution, conversion, or other
    high-level operations.  */
 
 tree
 build_cxx_call (tree fn, int nargs, tree *argarray,
-               tsubst_flags_t complain)
+               tsubst_flags_t complain, tree orig_fndecl)
 {
   tree fndecl;
 
@@ -9120,11 +9122,13 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
   SET_EXPR_LOCATION (fn, loc);
 
   fndecl = get_callee_fndecl (fn);
+  if (!orig_fndecl)
+    orig_fndecl = fndecl;
 
   /* Check that arguments to builtin functions match the expectations.  */
   if (fndecl
       && !processing_template_decl
-      && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
+      && fndecl_built_in_p (fndecl))
     {
       int i;
 
@@ -9134,7 +9138,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
        argarray[i] = maybe_constant_value (argarray[i]);
 
       if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
-                                            nargs, argarray))
+                                            orig_fndecl, nargs, argarray))
        return error_mark_node;
     }
 
index 9c0f3949c685fb989ae37451f01e2fcf169ee057..8fc3fc1f78bad743116bbce549c1e41f080f7791 100644 (file)
@@ -6257,7 +6257,8 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool,
                                                        tsubst_flags_t);
 extern tree in_charge_arg_for_name             (tree);
 extern tree build_cxx_call                     (tree, int, tree *,
-                                                tsubst_flags_t);
+                                                tsubst_flags_t,
+                                                tree = NULL_TREE);
 extern bool is_std_init_list                   (tree);
 extern bool is_list_ctor                       (tree);
 extern void validate_conversion_obstack                (void);
@@ -7391,7 +7392,8 @@ extern tree get_member_function_from_ptrfunc      (tree *, tree, tsubst_flags_t);
 extern tree cp_build_function_call_nary         (tree, tsubst_flags_t, ...)
                                                ATTRIBUTE_SENTINEL;
 extern tree cp_build_function_call_vec         (tree, vec<tree, va_gc> **,
-                                                tsubst_flags_t);
+                                                tsubst_flags_t,
+                                                tree = NULL_TREE);
 extern tree build_x_binary_op                  (const op_location_t &,
                                                 enum tree_code, tree,
                                                 enum tree_code, tree,
index f427c4f4d3e464b1270adce8cb0523cc8c8b41ac..d549450a605fa823a1c4054003025bc18447cc64 100644 (file)
@@ -3773,11 +3773,11 @@ build_function_call (location_t /*loc*/,
 tree
 build_function_call_vec (location_t /*loc*/, vec<location_t> /*arg_loc*/,
                         tree function, vec<tree, va_gc> *params,
-                        vec<tree, va_gc> * /*origtypes*/)
+                        vec<tree, va_gc> * /*origtypes*/, tree orig_function)
 {
   vec<tree, va_gc> *orig_params = params;
   tree ret = cp_build_function_call_vec (function, &params,
-                                        tf_warning_or_error);
+                                        tf_warning_or_error, orig_function);
 
   /* cp_build_function_call_vec can reallocate PARAMS by adding
      default arguments.  That should never happen here.  Verify
@@ -3818,13 +3818,15 @@ cp_build_function_call_nary (tree function, tsubst_flags_t complain, ...)
   return ret;
 }
 
-/* Build a function call using a vector of arguments.  PARAMS may be
-   NULL if there are no parameters.  This changes the contents of
-   PARAMS.  */
+/* Build a function call using a vector of arguments.
+   If FUNCTION is the result of resolving an overloaded target built-in,
+   ORIG_FNDECL is the original function decl, otherwise it is null.
+   PARAMS may be NULL if there are no parameters.  This changes the
+   contents of PARAMS.  */
 
 tree
 cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
-                           tsubst_flags_t complain)
+                           tsubst_flags_t complain, tree orig_fndecl)
 {
   tree fntype, fndecl;
   int is_method;
@@ -3949,7 +3951,7 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
   bool warned_p = check_function_arguments (input_location, fndecl, fntype,
                                            nargs, argarray, NULL);
 
-  ret = build_cxx_call (function, nargs, argarray, complain);
+  ret = build_cxx_call (function, nargs, argarray, complain, orig_fndecl);
 
   if (warned_p)
     {
index 0250cf58e72b4df8fec19cfb4399ed0e2594342b..a86c210d4fe390bd0356b6e50ba7c6c34a36239a 100644 (file)
@@ -11567,6 +11567,21 @@ another @code{CALL_EXPR}.
 @var{arglist} really has type @samp{VEC(tree,gc)*}
 @end deftypefn
 
+@deftypefn {Target Hook} bool TARGET_CHECK_BUILTIN_CALL (location_t @var{loc}, vec<location_t> @var{arg_loc}, tree @var{fndecl}, tree @var{orig_fndecl}, unsigned int @var{nargs}, tree *@var{args})
+Perform semantic checking on a call to a machine-specific built-in
+function after its arguments have been constrained to the function
+signature.  Return true if the call is valid, otherwise report an error
+and return false.
+
+This hook is called after @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}.
+The call was originally to built-in function @var{orig_fndecl},
+but after the optional @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}
+step is now to built-in function @var{fndecl}.  @var{loc} is the
+location of the call and @var{args} is an array of function arguments,
+of which there are @var{nargs}.  @var{arg_loc} specifies the location
+of each argument.
+@end deftypefn
+
 @deftypefn {Target Hook} tree TARGET_FOLD_BUILTIN (tree @var{fndecl}, int @var{n_args}, tree *@var{argp}, bool @var{ignore})
 Fold a call to a machine specific built-in function that was set up by
 @samp{TARGET_INIT_BUILTINS}.  @var{fndecl} is the declaration of the
index 0b77dd8eb46dc53fc585d7b3eac9805c6ed79951..06dfcda35abea7396c288a59c38ee4ef57c6fef6 100644 (file)
@@ -7938,6 +7938,8 @@ to by @var{ce_info}.
 
 @hook TARGET_RESOLVE_OVERLOADED_BUILTIN
 
+@hook TARGET_CHECK_BUILTIN_CALL
+
 @hook TARGET_FOLD_BUILTIN
 
 @hook TARGET_GIMPLE_FOLD_BUILTIN
index 01609136848fc157a47a93a0267c03524fe9383e..f9446fa05a22c79154c2ef36d3d8aea48a5efcc6 100644 (file)
@@ -2397,6 +2397,24 @@ another @code{CALL_EXPR}.\n\
 @var{arglist} really has type @samp{VEC(tree,gc)*}",
  tree, (unsigned int /*location_t*/ loc, tree fndecl, void *arglist), NULL)
 
+DEFHOOK
+(check_builtin_call,
+ "Perform semantic checking on a call to a machine-specific built-in\n\
+function after its arguments have been constrained to the function\n\
+signature.  Return true if the call is valid, otherwise report an error\n\
+and return false.\n\
+\n\
+This hook is called after @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}.\n\
+The call was originally to built-in function @var{orig_fndecl},\n\
+but after the optional @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}\n\
+step is now to built-in function @var{fndecl}.  @var{loc} is the\n\
+location of the call and @var{args} is an array of function arguments,\n\
+of which there are @var{nargs}.  @var{arg_loc} specifies the location\n\
+of each argument.",
+ bool, (location_t loc, vec<location_t> arg_loc, tree fndecl,
+       tree orig_fndecl, unsigned int nargs, tree *args),
+ NULL)
+
 /* Fold a target-specific builtin to a tree valid for both GIMPLE
    and GENERIC.  */
 DEFHOOK