| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /* GCC-StarPU
- Copyright (C) 2012 Inria
- GCC-StarPU 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 of the License, or
- (at your option) any later version.
- GCC-StarPU 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-StarPU. If not, see <http://www.gnu.org/licenses/>. */
- /* Use extensions of the GNU C Library. */
- #define _GNU_SOURCE 1
- #include <starpu-gcc/config.h>
- /* We must include starpu.h here, otherwise gcc will complain about a poisoned
- malloc in xmmintrin.h. */
- #include <starpu.h>
- #include <gcc-plugin.h>
- #include <plugin-version.h>
- #include <plugin.h>
- #include <cpplib.h>
- #include <tree.h>
- #include <tree-pass.h>
- #include <gimple.h>
- #include <diagnostic.h>
- #include <cgraph.h>
- #include <starpu-gcc/utils.h>
- #include <starpu-gcc/tasks.h>
- /* Return true if there exists a `starpu_vector_data_register' call for VAR
- before GSI in its basic block. */
- static bool
- registration_in_bb_p (gimple_stmt_iterator gsi, tree var)
- {
- gcc_assert (SSA_VAR_P (var));
- tree register_fn_name;
- register_fn_name = get_identifier ("starpu_vector_data_register");
- local_define (bool, registration_function_p, (const_tree obj))
- {
- /* TODO: Compare against the real fndecl. */
- return (obj != NULL_TREE
- && TREE_CODE (obj) == FUNCTION_DECL
- && DECL_NAME (obj) == register_fn_name);
- };
- bool found;
- for (found = false;
- !gsi_end_p (gsi) && !found;
- gsi_prev (&gsi))
- {
- gimple stmt;
- stmt = gsi_stmt (gsi);
- if (is_gimple_call (stmt))
- {
- tree fn = gimple_call_fndecl (stmt);
- if (registration_function_p (fn))
- {
- tree arg = gimple_call_arg (stmt, 2);
- if (is_gimple_address (arg))
- arg = TREE_OPERAND (arg, 0);
- if (((TREE_CODE (arg) == VAR_DECL
- || TREE_CODE (arg) == VAR_DECL)
- && refs_may_alias_p (arg, var))
- /* Both VAR and ARG should be SSA names, otherwise, if ARG
- is a VAR_DECL, `ptr_derefs_may_alias_p' will
- conservatively assume that they may alias. */
- || (TREE_CODE (var) == SSA_NAME
- && TREE_CODE (arg) != VAR_DECL
- && ptr_derefs_may_alias_p (arg, var)))
- {
- if (verbose_output_p)
- {
- var = TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var;
- inform (gimple_location (stmt),
- "found registration of variable %qE",
- DECL_NAME (var));
- }
- found = true;
- }
- }
- }
- }
- return found;
- }
- /* Return true if BB is dominated by a registration of VAR. */
- static bool
- dominated_by_registration (gimple_stmt_iterator gsi, tree var)
- {
- /* Is there a registration call for VAR in GSI's basic block? */
- if (registration_in_bb_p (gsi, var))
- return true;
- edge e;
- edge_iterator ei;
- bool found = false;
- /* If every incoming edge is dominated by a registration, then we're
- fine.
- FIXME: This triggers false positives when registration is done in a
- loop, because there's always an edge through which no registration
- happens--the edge corresponding to the case where the loop is not
- entered. */
- FOR_EACH_EDGE (e, ei, gsi_bb (gsi)->preds)
- {
- if (!dominated_by_registration (gsi_last_bb (e->src), var))
- return false;
- else
- found = true;
- }
- return found;
- }
- /* Return true if NAME aliases a global variable or a PARM_DECL. Note that,
- for the former, `ptr_deref_may_alias_global_p' is way too conservative,
- hence this approach. */
- static bool
- ssa_name_aliases_global_or_parm_p (const_tree name)
- {
- gcc_assert (TREE_CODE (name) == SSA_NAME);
- if (TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL)
- return true;
- else
- {
- gimple def_stmt;
- def_stmt = SSA_NAME_DEF_STMT (name);
- if (is_gimple_assign (def_stmt))
- {
- tree rhs = gimple_assign_rhs1 (def_stmt);
- if (TREE_CODE (rhs) == VAR_DECL
- && (DECL_EXTERNAL (rhs) || TREE_STATIC (rhs)))
- return true;
- }
- }
- return false;
- }
- /* Validate the arguments passed to tasks in FN's body. */
- static void
- validate_task_invocations (tree fn)
- {
- gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
- const struct cgraph_node *cgraph;
- const struct cgraph_edge *callee;
- cgraph = cgraph_get_node (fn);
- /* When a definition of IMPL is available, check its callees. */
- if (cgraph != NULL)
- for (callee = cgraph->callees;
- callee != NULL;
- callee = callee->next_callee)
- {
- if (task_p (callee->callee->decl))
- {
- unsigned i;
- gimple call_stmt = callee->call_stmt;
- for (i = 0; i < gimple_call_num_args (call_stmt); i++)
- {
- tree arg = gimple_call_arg (call_stmt, i);
- if (TREE_CODE (arg) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (arg, 0)) == VAR_DECL
- && (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0)))
- == ARRAY_TYPE))
- /* This is a "pointer-to-array" of a variable, so what we
- really care about is the variable itself. */
- arg = TREE_OPERAND (arg, 0);
- if ((POINTER_TYPE_P (TREE_TYPE (arg))
- || (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE))
- && ((TREE_CODE (arg) == VAR_DECL
- && !TREE_STATIC (arg)
- && !DECL_EXTERNAL (arg)
- && !TREE_NO_WARNING (arg))
- || (TREE_CODE (arg) == SSA_NAME
- && !ssa_name_aliases_global_or_parm_p (arg))))
- {
- if (!dominated_by_registration (gsi_for_stmt (call_stmt),
- arg))
- {
- if (TREE_CODE (arg) == SSA_NAME)
- {
- tree var = SSA_NAME_VAR (arg);
- if (DECL_NAME (var) != NULL)
- arg = var;
- /* TODO: Check whether we can get the original
- variable name via ARG's DEF_STMT. */
- }
- if (TREE_CODE (arg) == VAR_DECL
- && DECL_NAME (arg) != NULL_TREE)
- warning_at (gimple_location (call_stmt), 0,
- "variable %qE may be used unregistered",
- DECL_NAME (arg));
- else
- warning_at (gimple_location (call_stmt), 0,
- "argument %i may be used unregistered",
- i);
- }
- }
- }
- }
- }
- }
- /* A pass to warn about possibly unregistered task arguments. */
- static unsigned int
- warn_starpu_unregistered (void)
- {
- tree fndecl;
- fndecl = current_function_decl;
- gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
- if (!task_p (fndecl))
- validate_task_invocations (fndecl);
- return 0;
- }
- struct opt_pass pass_warn_starpu_unregistered =
- {
- designated_field_init (type, GIMPLE_PASS),
- designated_field_init (name, "warn_starpu_unregistered"),
- designated_field_init (gate, NULL),
- designated_field_init (execute, warn_starpu_unregistered),
- /* The rest is zeroed. */
- };
|