diff options
author | Andrew MacLeod <amacleod@redhat.com> | 2013-09-17 17:22:05 +0000 |
---|---|---|
committer | Andrew Macleod <amacleod@gcc.gnu.org> | 2013-09-17 17:22:05 +0000 |
commit | c152901f5e1082de4ede3bc98c7ede2dea361e8d (patch) | |
tree | ba3badb1ebc6b822039de7c1796a0f9d5805f0c9 /gcc | |
parent | cdb87c08f66da0d5b6ae8ee9b3d2f917813a3cf1 (diff) | |
download | gcc-c152901f5e1082de4ede3bc98c7ede2dea361e8d.zip gcc-c152901f5e1082de4ede3bc98c7ede2dea361e8d.tar.gz gcc-c152901f5e1082de4ede3bc98c7ede2dea361e8d.tar.bz2 |
tree-flow.h (ssa_undefined_value_p): Remove prototype.
2013-09-17 Andrew MacLeod <amacleod@redhat.com>
* tree-flow.h (ssa_undefined_value_p): Remove prototype.
* tree-ssa.c (ssa_undefined_value_p): Move pass independent parts here.
(warn_uninit, warn_uninitialized_vars, execute_early_warn_uninitialized,
make_pass_early_warn_uninitialized): Move to tree-ssa-uninit.c.
* tree-ssa-uninit.c (ssa_undefined_value_p): Move to tree-ssa.c
(has_undefined_value_p): New. Pass dependant parts of
ssa_undefined_value_p.
(uninit_undefined_value_p): Use has_undefined_value_p.
(warn_uninit, warn_uninitialized_vars, execute_early_warn_uninitialized,
make_pass_early_warn_uninitialized): Move from tree-ssa.c
* tree-ssa.h: Adjust prototypes
From-SVN: r202659
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/tree-flow.h | 3 | ||||
-rw-r--r-- | gcc/tree-ssa-uninit.c | 239 | ||||
-rw-r--r-- | gcc/tree-ssa.c | 234 | ||||
-rw-r--r-- | gcc/tree-ssa.h | 3 |
5 files changed, 254 insertions, 239 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3f3a1bc..eb162f4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2013-09-17 Andrew MacLeod <amacleod@redhat.com> + + * tree-flow.h (ssa_undefined_value_p): Remove prototype. + * tree-ssa.c (ssa_undefined_value_p): Move pass independent parts here. + (warn_uninit, warn_uninitialized_vars, execute_early_warn_uninitialized, + make_pass_early_warn_uninitialized): Move to tree-ssa-uninit.c. + * tree-ssa-uninit.c (ssa_undefined_value_p): Move to tree-ssa.c + (has_undefined_value_p): New. Pass dependant parts of + ssa_undefined_value_p. + (uninit_undefined_value_p): Use has_undefined_value_p. + (warn_uninit, warn_uninitialized_vars, execute_early_warn_uninitialized, + make_pass_early_warn_uninitialized): Move from tree-ssa.c + * tree-ssa.h: Adjust prototypes + 2013-09-17 Jan Hubicka <jh@suse.cz> PR middle-end/58329 diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 9c5d979..2f64abc 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -421,9 +421,6 @@ extern bool gimple_seq_may_fallthru (gimple_seq); extern bool gimple_stmt_may_fallthru (gimple); extern bool gimple_check_call_matching_types (gimple, tree, bool); -/* In tree-ssa-uninit.c */ -extern bool ssa_undefined_value_p (tree); - /* In tree-into-ssa.c */ void update_ssa (unsigned); void delete_update_ssa (void); diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index ae30e24..bd46ddf 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -74,46 +74,173 @@ get_mask_first_set_bit (unsigned mask) } #define MASK_FIRST_SET_BIT(mask) get_mask_first_set_bit (mask) - /* Return true if T, an SSA_NAME, has an undefined value. */ - -bool -ssa_undefined_value_p (tree t) +static bool +has_undefined_value_p (tree t) { - tree var = SSA_NAME_VAR (t); - - if (!var) - ; - /* Parameters get their initial value from the function entry. */ - else if (TREE_CODE (var) == PARM_DECL) - return false; - /* When returning by reference the return address is actually a hidden - parameter. */ - else if (TREE_CODE (var) == RESULT_DECL && DECL_BY_REFERENCE (var)) - return false; - /* Hard register variables get their initial value from the ether. */ - else if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var)) - return false; - - /* The value is undefined iff its definition statement is empty. */ - return (gimple_nop_p (SSA_NAME_DEF_STMT (t)) + return (ssa_undefined_value_p (t) || (possibly_undefined_names && pointer_set_contains (possibly_undefined_names, t))); } -/* Like ssa_undefined_value_p, but don't return true if TREE_NO_WARNING + + +/* Like has_undefined_value_p, but don't return true if TREE_NO_WARNING is set on SSA_NAME_VAR. */ static inline bool -uninit_undefined_value_p (tree t) -{ - if (!ssa_undefined_value_p (t)) +uninit_undefined_value_p (tree t) { + if (!has_undefined_value_p (t)) return false; if (SSA_NAME_VAR (t) && TREE_NO_WARNING (SSA_NAME_VAR (t))) return false; return true; } +/* Emit warnings for uninitialized variables. This is done in two passes. + + The first pass notices real uses of SSA names with undefined values. + Such uses are unconditionally uninitialized, and we can be certain that + such a use is a mistake. This pass is run before most optimizations, + so that we catch as many as we can. + + The second pass follows PHI nodes to find uses that are potentially + uninitialized. In this case we can't necessarily prove that the use + is really uninitialized. This pass is run after most optimizations, + so that we thread as many jumps and possible, and delete as much dead + code as possible, in order to reduce false positives. We also look + again for plain uninitialized variables, since optimization may have + changed conditionally uninitialized to unconditionally uninitialized. */ + +/* Emit a warning for EXPR based on variable VAR at the point in the + program T, an SSA_NAME, is used being uninitialized. The exact + warning text is in MSGID and LOCUS may contain a location or be null. + WC is the warning code. */ + +static void +warn_uninit (enum opt_code wc, tree t, + tree expr, tree var, const char *gmsgid, void *data) +{ + gimple context = (gimple) data; + location_t location, cfun_loc; + expanded_location xloc, floc; + + if (!has_undefined_value_p (t)) + return; + + /* TREE_NO_WARNING either means we already warned, or the front end + wishes to suppress the warning. */ + if ((context + && (gimple_no_warning_p (context) + || (gimple_assign_single_p (context) + && TREE_NO_WARNING (gimple_assign_rhs1 (context))))) + || TREE_NO_WARNING (expr)) + return; + + location = (context != NULL && gimple_has_location (context)) + ? gimple_location (context) + : DECL_SOURCE_LOCATION (var); + location = linemap_resolve_location (line_table, location, + LRK_SPELLING_LOCATION, + NULL); + cfun_loc = DECL_SOURCE_LOCATION (cfun->decl); + xloc = expand_location (location); + floc = expand_location (cfun_loc); + if (warning_at (location, wc, gmsgid, expr)) + { + TREE_NO_WARNING (expr) = 1; + + if (location == DECL_SOURCE_LOCATION (var)) + return; + if (xloc.file != floc.file + || linemap_location_before_p (line_table, + location, cfun_loc) + || linemap_location_before_p (line_table, + cfun->function_end_locus, + location)) + inform (DECL_SOURCE_LOCATION (var), "%qD was declared here", var); + } +} + +static unsigned int +warn_uninitialized_vars (bool warn_possibly_uninitialized) +{ + gimple_stmt_iterator gsi; + basic_block bb; + + FOR_EACH_BB (bb) + { + bool always_executed = dominated_by_p (CDI_POST_DOMINATORS, + single_succ (ENTRY_BLOCK_PTR), bb); + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + use_operand_p use_p; + ssa_op_iter op_iter; + tree use; + + if (is_gimple_debug (stmt)) + continue; + + /* We only do data flow with SSA_NAMEs, so that's all we + can warn about. */ + FOR_EACH_SSA_USE_OPERAND (use_p, stmt, op_iter, SSA_OP_USE) + { + use = USE_FROM_PTR (use_p); + if (always_executed) + warn_uninit (OPT_Wuninitialized, use, + SSA_NAME_VAR (use), SSA_NAME_VAR (use), + "%qD is used uninitialized in this function", + stmt); + else if (warn_possibly_uninitialized) + warn_uninit (OPT_Wmaybe_uninitialized, use, + SSA_NAME_VAR (use), SSA_NAME_VAR (use), + "%qD may be used uninitialized in this function", + stmt); + } + + /* For memory the only cheap thing we can do is see if we + have a use of the default def of the virtual operand. + ??? Note that at -O0 we do not have virtual operands. + ??? Not so cheap would be to use the alias oracle via + walk_aliased_vdefs, if we don't find any aliasing vdef + warn as is-used-uninitialized, if we don't find an aliasing + vdef that kills our use (stmt_kills_ref_p), warn as + may-be-used-uninitialized. But this walk is quadratic and + so must be limited which means we would miss warning + opportunities. */ + use = gimple_vuse (stmt); + if (use + && gimple_assign_single_p (stmt) + && !gimple_vdef (stmt) + && SSA_NAME_IS_DEFAULT_DEF (use)) + { + tree rhs = gimple_assign_rhs1 (stmt); + tree base = get_base_address (rhs); + + /* Do not warn if it can be initialized outside this function. */ + if (TREE_CODE (base) != VAR_DECL + || DECL_HARD_REGISTER (base) + || is_global_var (base)) + continue; + + if (always_executed) + warn_uninit (OPT_Wuninitialized, use, + gimple_assign_rhs1 (stmt), base, + "%qE is used uninitialized in this function", + stmt); + else if (warn_possibly_uninitialized) + warn_uninit (OPT_Wmaybe_uninitialized, use, + gimple_assign_rhs1 (stmt), base, + "%qE may be used uninitialized in this function", + stmt); + } + } + } + + return 0; +} + /* Checks if the operand OPND of PHI is defined by another phi with one operand defined by this PHI, but the rest operands are all defined. If yes, @@ -2084,3 +2211,65 @@ make_pass_late_warn_uninitialized (gcc::context *ctxt) { return new pass_late_warn_uninitialized (ctxt); } + + +static unsigned int +execute_early_warn_uninitialized (void) +{ + /* Currently, this pass runs always but + execute_late_warn_uninitialized only runs with optimization. With + optimization we want to warn about possible uninitialized as late + as possible, thus don't do it here. However, without + optimization we need to warn here about "may be uninitialized". + */ + calculate_dominance_info (CDI_POST_DOMINATORS); + + warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize); + + /* Post-dominator information can not be reliably updated. Free it + after the use. */ + + free_dominance_info (CDI_POST_DOMINATORS); + return 0; +} + + +namespace { + +const pass_data pass_data_early_warn_uninitialized = +{ + GIMPLE_PASS, /* type */ + "*early_warn_uninitialized", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + true, /* has_gate */ + true, /* has_execute */ + TV_TREE_UNINIT, /* tv_id */ + PROP_ssa, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_early_warn_uninitialized : public gimple_opt_pass +{ +public: + pass_early_warn_uninitialized(gcc::context *ctxt) + : gimple_opt_pass(pass_data_early_warn_uninitialized, ctxt) + {} + + /* opt_pass methods: */ + bool gate () { return gate_warn_uninitialized (); } + unsigned int execute () { return execute_early_warn_uninitialized (); } + +}; // class pass_early_warn_uninitialized + +} // anon namespace + +gimple_opt_pass * +make_pass_early_warn_uninitialized (gcc::context *ctxt) +{ + return new pass_early_warn_uninitialized (ctxt); +} + + diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 461bb52..8146e1f 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -1193,6 +1193,31 @@ tree_ssa_strip_useless_type_conversions (tree exp) } +/* Return true if T, an SSA_NAME, has an undefined value. */ + +bool +ssa_undefined_value_p (tree t) +{ + tree var = SSA_NAME_VAR (t); + + if (!var) + ; + /* Parameters get their initial value from the function entry. */ + else if (TREE_CODE (var) == PARM_DECL) + return false; + /* When returning by reference the return address is actually a hidden + parameter. */ + else if (TREE_CODE (var) == RESULT_DECL && DECL_BY_REFERENCE (var)) + return false; + /* Hard register variables get their initial value from the ether. */ + else if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var)) + return false; + + /* The value is undefined iff its definition statement is empty. */ + return gimple_nop_p (SSA_NAME_DEF_STMT (t)); +} + + /* Internal helper for walk_use_def_chains. VAR, FN and DATA are as described in walk_use_def_chains. @@ -1301,215 +1326,6 @@ walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data, } } - -/* Emit warnings for uninitialized variables. This is done in two passes. - - The first pass notices real uses of SSA names with undefined values. - Such uses are unconditionally uninitialized, and we can be certain that - such a use is a mistake. This pass is run before most optimizations, - so that we catch as many as we can. - - The second pass follows PHI nodes to find uses that are potentially - uninitialized. In this case we can't necessarily prove that the use - is really uninitialized. This pass is run after most optimizations, - so that we thread as many jumps and possible, and delete as much dead - code as possible, in order to reduce false positives. We also look - again for plain uninitialized variables, since optimization may have - changed conditionally uninitialized to unconditionally uninitialized. */ - -/* Emit a warning for EXPR based on variable VAR at the point in the - program T, an SSA_NAME, is used being uninitialized. The exact - warning text is in MSGID and LOCUS may contain a location or be null. - WC is the warning code. */ - -void -warn_uninit (enum opt_code wc, tree t, - tree expr, tree var, const char *gmsgid, void *data) -{ - gimple context = (gimple) data; - location_t location, cfun_loc; - expanded_location xloc, floc; - - if (!ssa_undefined_value_p (t)) - return; - - /* TREE_NO_WARNING either means we already warned, or the front end - wishes to suppress the warning. */ - if ((context - && (gimple_no_warning_p (context) - || (gimple_assign_single_p (context) - && TREE_NO_WARNING (gimple_assign_rhs1 (context))))) - || TREE_NO_WARNING (expr)) - return; - - location = (context != NULL && gimple_has_location (context)) - ? gimple_location (context) - : DECL_SOURCE_LOCATION (var); - location = linemap_resolve_location (line_table, location, - LRK_SPELLING_LOCATION, - NULL); - cfun_loc = DECL_SOURCE_LOCATION (cfun->decl); - xloc = expand_location (location); - floc = expand_location (cfun_loc); - if (warning_at (location, wc, gmsgid, expr)) - { - TREE_NO_WARNING (expr) = 1; - - if (location == DECL_SOURCE_LOCATION (var)) - return; - if (xloc.file != floc.file - || linemap_location_before_p (line_table, - location, cfun_loc) - || linemap_location_before_p (line_table, - cfun->function_end_locus, - location)) - inform (DECL_SOURCE_LOCATION (var), "%qD was declared here", var); - } -} - -unsigned int -warn_uninitialized_vars (bool warn_possibly_uninitialized) -{ - gimple_stmt_iterator gsi; - basic_block bb; - - FOR_EACH_BB (bb) - { - bool always_executed = dominated_by_p (CDI_POST_DOMINATORS, - single_succ (ENTRY_BLOCK_PTR), bb); - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple stmt = gsi_stmt (gsi); - use_operand_p use_p; - ssa_op_iter op_iter; - tree use; - - if (is_gimple_debug (stmt)) - continue; - - /* We only do data flow with SSA_NAMEs, so that's all we - can warn about. */ - FOR_EACH_SSA_USE_OPERAND (use_p, stmt, op_iter, SSA_OP_USE) - { - use = USE_FROM_PTR (use_p); - if (always_executed) - warn_uninit (OPT_Wuninitialized, use, - SSA_NAME_VAR (use), SSA_NAME_VAR (use), - "%qD is used uninitialized in this function", - stmt); - else if (warn_possibly_uninitialized) - warn_uninit (OPT_Wmaybe_uninitialized, use, - SSA_NAME_VAR (use), SSA_NAME_VAR (use), - "%qD may be used uninitialized in this function", - stmt); - } - - /* For memory the only cheap thing we can do is see if we - have a use of the default def of the virtual operand. - ??? Note that at -O0 we do not have virtual operands. - ??? Not so cheap would be to use the alias oracle via - walk_aliased_vdefs, if we don't find any aliasing vdef - warn as is-used-uninitialized, if we don't find an aliasing - vdef that kills our use (stmt_kills_ref_p), warn as - may-be-used-uninitialized. But this walk is quadratic and - so must be limited which means we would miss warning - opportunities. */ - use = gimple_vuse (stmt); - if (use - && gimple_assign_single_p (stmt) - && !gimple_vdef (stmt) - && SSA_NAME_IS_DEFAULT_DEF (use)) - { - tree rhs = gimple_assign_rhs1 (stmt); - tree base = get_base_address (rhs); - - /* Do not warn if it can be initialized outside this function. */ - if (TREE_CODE (base) != VAR_DECL - || DECL_HARD_REGISTER (base) - || is_global_var (base)) - continue; - - if (always_executed) - warn_uninit (OPT_Wuninitialized, use, - gimple_assign_rhs1 (stmt), base, - "%qE is used uninitialized in this function", - stmt); - else if (warn_possibly_uninitialized) - warn_uninit (OPT_Wmaybe_uninitialized, use, - gimple_assign_rhs1 (stmt), base, - "%qE may be used uninitialized in this function", - stmt); - } - } - } - - return 0; -} - -static unsigned int -execute_early_warn_uninitialized (void) -{ - /* Currently, this pass runs always but - execute_late_warn_uninitialized only runs with optimization. With - optimization we want to warn about possible uninitialized as late - as possible, thus don't do it here. However, without - optimization we need to warn here about "may be uninitialized". - */ - calculate_dominance_info (CDI_POST_DOMINATORS); - - warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize); - - /* Post-dominator information can not be reliably updated. Free it - after the use. */ - - free_dominance_info (CDI_POST_DOMINATORS); - return 0; -} - -static bool -gate_warn_uninitialized (void) -{ - return warn_uninitialized != 0; -} - -namespace { - -const pass_data pass_data_early_warn_uninitialized = -{ - GIMPLE_PASS, /* type */ - "*early_warn_uninitialized", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_gate */ - true, /* has_execute */ - TV_TREE_UNINIT, /* tv_id */ - PROP_ssa, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ -}; - -class pass_early_warn_uninitialized : public gimple_opt_pass -{ -public: - pass_early_warn_uninitialized(gcc::context *ctxt) - : gimple_opt_pass(pass_data_early_warn_uninitialized, ctxt) - {} - - /* opt_pass methods: */ - bool gate () { return gate_warn_uninitialized (); } - unsigned int execute () { return execute_early_warn_uninitialized (); } - -}; // class pass_early_warn_uninitialized - -} // anon namespace - -gimple_opt_pass * -make_pass_early_warn_uninitialized (gcc::context *ctxt) -{ - return new pass_early_warn_uninitialized (ctxt); -} - /* If necessary, rewrite the base of the reference tree *TP from a MEM_REF to a plain or converted symbol. */ diff --git a/gcc/tree-ssa.h b/gcc/tree-ssa.h index 457fd6b..1808b1c 100644 --- a/gcc/tree-ssa.h +++ b/gcc/tree-ssa.h @@ -58,8 +58,7 @@ extern tree tree_ssa_strip_useless_type_conversions (tree); typedef bool (*walk_use_def_chains_fn) (tree, gimple, void *); extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool); -extern void warn_uninit (enum opt_code, tree, tree, tree, const char *, void *); -extern unsigned int warn_uninitialized_vars (bool); +extern bool ssa_undefined_value_p (tree); extern void execute_update_addresses_taken (void); /* Given an edge_var_map V, return the PHI arg definition. */ |