Hi Richard, I was trying to have a look at PR35503. The attached patch tries to warn when an argument is passed to a restrict-qualified parameter and the argument could alias with other argument.
For the following test-case: int f2(int *restrict x, int *y); void f(void) { int a; f2 (&a, &a); } The patch warns: test-1.c: In function âfâ: test-1.c:6:3: warning: Passing argument 1 to restrict-qualified parameter may alias with argument 2 [-Wrestrict] f2 (&a, &a); ^~~~~~~~~~~ However it gives false positives if arg is a string constant as in following case: int foo (char *restrict buf, char *restrict fmt, ...); int f(void) { char buf[10]; foo (buf, "%s-%s", buf, "hello"); } The patch gives false positives for argument 2: test-3.c: In function âfâ: test-3.c:6:3: warning: Passing argument 1 to restrict-qualified parameter may alias with argument 3 [-Wrestrict] foo (buf, "%s-%s", buf, "hello"); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test-3.c:6:3: warning: Passing argument 2 to restrict-qualified parameter may alias with argument 1 [-Wrestrict] test-3.c:6:3: warning: Passing argument 2 to restrict-qualified parameter may alias with argument 3 [-Wrestrict] test-3.c:6:3: warning: Passing argument 2 to restrict-qualified parameter may alias with argument 4 [-Wrestrict] I am using compute_may_aliases() to obtain alias analysis info, and then using ptr_derefs_may_alias_p(arg, current_arg) to check if the arguments could potentially alias. Is that incorrect ? Thanks, Prathamesh
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 8d7cc51..5d8263d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1549,6 +1549,7 @@ OBJS = \ varpool.o \ vmsdbgout.o \ vtable-verify.o \ + warn-restrict.o \ web.o \ wide-int.o \ wide-int-print.o \ diff --git a/gcc/common.opt b/gcc/common.opt index 65a9762..afb2327 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -732,6 +732,11 @@ Wmaybe-uninitialized Common Var(warn_maybe_uninitialized) Warning EnabledBy(Wuninitialized) Warn about maybe uninitialized automatic variables. +Wrestrict +Common Var(warn_restrict) Warning EanbledBy(Wall) +Warn when a pointer argument is passed to a parameter qualified with restrict, +and it potentially aliases with another arguments. + Wunreachable-code Common Ignore Warning Does nothing. Preserved for backward compatibility. diff --git a/gcc/passes.def b/gcc/passes.def index 533157d..2cccd6d 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -141,6 +141,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_ipa_increase_alignment); NEXT_PASS (pass_ipa_tm); NEXT_PASS (pass_ipa_lower_emutls); + NEXT_PASS (pass_ipa_warn_restrict); TERMINATE_PASS_LIST (all_small_ipa_passes) INSERT_PASSES_AFTER (all_regular_ipa_passes) diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index c0059de..90d06b5 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -485,6 +485,7 @@ extern ipa_opt_pass_d *make_pass_ipa_whole_program_visibility (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_increase_alignment (gcc::context *ctxt); +extern simple_ipa_opt_pass *make_pass_ipa_warn_restrict (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_free_inline_summary (gcc::context diff --git a/gcc/warn-restrict.c b/gcc/warn-restrict.c new file mode 100644 index 0000000..fa6d9b1 --- /dev/null +++ b/gcc/warn-restrict.c @@ -0,0 +1,131 @@ +/* +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "target.h" +#include "tree.h" +#include "gimple.h" +#include "tree-pass.h" +#include "tree-streamer.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "calls.h" +#include "cfganal.h" +#include "tree-eh.h" +#include "gimple-iterator.h" +#include "gimple-walk.h" +#include "tree-cfg.h" +#include "tree-ssa-loop-niter.h" +#include "langhooks.h" +#include "ipa-utils.h" +#include "gimple-pretty-print.h" +#include "cfgloop.h" +#include "tree-scalar-evolution.h" +#include "intl.h" +#include "opts.h" +#include "fold-const.h" + +static void +do_warn_restrict (function *fun) +{ + push_cfun (fun); + compute_may_aliases (); + + cgraph_node *cnode = cgraph_node::get (current_function_decl); + for (cgraph_edge *e = cnode->callees; e; e = e->next_callee) + { + cgraph_node *callee = e->callee->function_symbol (); + tree callee_decl = callee->decl; + gcall *call_stmt = e->call_stmt; + + unsigned param_pos = 0; + for (tree t = TYPE_ARG_TYPES (TREE_TYPE (callee_decl)); t; t = TREE_CHAIN (t), param_pos++) + { + tree type = TREE_VALUE (t); + if (POINTER_TYPE_P (type) && TYPE_RESTRICT (type)) + { + tree arg = gimple_call_arg (call_stmt, param_pos); + gcc_assert (POINTER_TYPE_P (TREE_TYPE (arg))); + + for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++) + { + if (i == param_pos) + continue; + + tree current_arg = gimple_call_arg (call_stmt, i); + if (POINTER_TYPE_P (TREE_TYPE (current_arg)) + && ptr_derefs_may_alias_p (arg, current_arg)) + warning_at (gimple_location (call_stmt), OPT_Wrestrict, + "Passing argument %d to restrict-qualified parameter " + "may alias with argument %d", + param_pos + 1, i + 1); + } + } + } + } + + pop_cfun (); +} + +namespace { + +const pass_data pass_data_warn_restrict = +{ + SIMPLE_IPA_PASS, /* type */ + "*warn-restrict", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + 0, /* properties required */ + 0, /* properties provided */ + 0, /* properties destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_ipa_warn_restrict: public simple_ipa_opt_pass +{ +public: + pass_ipa_warn_restrict (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_warn_restrict, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) { return warn_restrict; } + virtual unsigned execute (function *); +}; // class pass_warn_function_noreturn + +unsigned +pass_ipa_warn_restrict::execute (function *) +{ + cgraph_node *cnode; + + FOR_EACH_DEFINED_FUNCTION (cnode) + do_warn_restrict (DECL_STRUCT_FUNCTION (cnode->decl)); + + return 0; +} + +} // anon namespace + +simple_ipa_opt_pass * +make_pass_ipa_warn_restrict (gcc::context *ctxt) +{ + return new pass_ipa_warn_restrict (ctxt); +}