Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-ssa-uninit.c @ 67:f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Mar 2011 17:18:12 +0900 |
parents | b7f97abdc517 |
children | 04ced10e8804 |
line wrap: on
line diff
--- a/gcc/tree-ssa-uninit.c Tue May 25 18:58:51 2010 +0900 +++ b/gcc/tree-ssa-uninit.c Tue Mar 22 17:18:12 2011 +0900 @@ -29,9 +29,7 @@ #include "langhooks.h" #include "basic-block.h" #include "output.h" -#include "expr.h" #include "function.h" -#include "diagnostic.h" #include "gimple-pretty-print.h" #include "bitmap.h" #include "pointer-set.h" @@ -42,7 +40,7 @@ #include "hashtab.h" #include "tree-dump.h" #include "tree-pass.h" -#include "toplev.h" +#include "diagnostic-core.h" #include "timevar.h" /* This implements the pass that does predicate aware warning on uses of @@ -94,6 +92,12 @@ if (TREE_CODE (var) == PARM_DECL) return false; + /* When returning by reference the return address is actually a hidden + parameter. */ + if (TREE_CODE (SSA_NAME_VAR (t)) == RESULT_DECL + && DECL_BY_REFERENCE (SSA_NAME_VAR (t))) + return false; + /* Hard register variables get their initial value from the ether. */ if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var)) return false; @@ -144,6 +148,9 @@ unsigned uninit_opnds = 0; n = gimple_phi_num_args (phi); + /* Bail out for phi with too many args. */ + if (n > 32) + return 0; for (i = 0; i < n; ++i) { @@ -485,17 +492,33 @@ opnd_edge = gimple_phi_arg_edge (phi, i); opnd = gimple_phi_arg_def (phi, i); - if (TREE_CODE (opnd) != SSA_NAME - || !ssa_undefined_value_p (opnd)) - VEC_safe_push (edge, heap, *edges, opnd_edge); + if (TREE_CODE (opnd) != SSA_NAME) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\n[CHECK] Found def edge %d in ", (int)i); + print_gimple_stmt (dump_file, phi, 0, 0); + } + VEC_safe_push (edge, heap, *edges, opnd_edge); + } else { gimple def = SSA_NAME_DEF_STMT (opnd); + if (gimple_code (def) == GIMPLE_PHI && dominated_by_p (CDI_DOMINATORS, gimple_bb (def), cd_root)) collect_phi_def_edges (def, cd_root, edges, visited_phis); + else if (!ssa_undefined_value_p (opnd)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\n[CHECK] Found def edge %d in ", (int)i); + print_gimple_stmt (dump_file, phi, 0, 0); + } + VEC_safe_push (edge, heap, *edges, opnd_edge); + } } } } @@ -761,6 +784,139 @@ unsigned uninit_opnds, struct pointer_set_t *visited_phis); +/* Returns true if all uninitialized opnds are pruned. Returns false + otherwise. PHI is the phi node with uninitialized operands, + UNINIT_OPNDS is the bitmap of the uninitialize operand positions, + FLAG_DEF is the statement defining the flag guarding the use of the + PHI output, BOUNDARY_CST is the const value used in the predicate + associated with the flag, CMP_CODE is the comparison code used in + the predicate, VISITED_PHIS is the pointer set of phis visited, and + VISITED_FLAG_PHIS is the pointer to the pointer set of flag definitions + that are also phis. + + Example scenario: + + BB1: + flag_1 = phi <0, 1> // (1) + var_1 = phi <undef, some_val> + + + BB2: + flag_2 = phi <0, flag_1, flag_1> // (2) + var_2 = phi <undef, var_1, var_1> + if (flag_2 == 1) + goto BB3; + + BB3: + use of var_2 // (3) + + Because some flag arg in (1) is not constant, if we do not look into the + flag phis recursively, it is conservatively treated as unknown and var_1 + is thought to be flowed into use at (3). Since var_1 is potentially uninitialized + a false warning will be emitted. Checking recursively into (1), the compiler can + find out that only some_val (which is defined) can flow into (3) which is OK. + +*/ + +static bool +prune_uninit_phi_opnds_in_unrealizable_paths ( + gimple phi, unsigned uninit_opnds, + gimple flag_def, tree boundary_cst, + enum tree_code cmp_code, + struct pointer_set_t *visited_phis, + bitmap *visited_flag_phis) +{ + unsigned i; + + for (i = 0; i < MIN (32, gimple_phi_num_args (flag_def)); i++) + { + tree flag_arg; + + if (!MASK_TEST_BIT (uninit_opnds, i)) + continue; + + flag_arg = gimple_phi_arg_def (flag_def, i); + if (!is_gimple_constant (flag_arg)) + { + gimple flag_arg_def, phi_arg_def; + tree phi_arg; + unsigned uninit_opnds_arg_phi; + + if (TREE_CODE (flag_arg) != SSA_NAME) + return false; + flag_arg_def = SSA_NAME_DEF_STMT (flag_arg); + if (gimple_code (flag_arg_def) != GIMPLE_PHI) + return false; + + phi_arg = gimple_phi_arg_def (phi, i); + if (TREE_CODE (phi_arg) != SSA_NAME) + return false; + + phi_arg_def = SSA_NAME_DEF_STMT (phi_arg); + if (gimple_code (phi_arg_def) != GIMPLE_PHI) + return false; + + if (gimple_bb (phi_arg_def) != gimple_bb (flag_arg_def)) + return false; + + if (!*visited_flag_phis) + *visited_flag_phis = BITMAP_ALLOC (NULL); + + if (bitmap_bit_p (*visited_flag_phis, + SSA_NAME_VERSION (gimple_phi_result (flag_arg_def)))) + return false; + + bitmap_set_bit (*visited_flag_phis, + SSA_NAME_VERSION (gimple_phi_result (flag_arg_def))); + + /* Now recursively prune the uninitialized phi args. */ + uninit_opnds_arg_phi = compute_uninit_opnds_pos (phi_arg_def); + if (!prune_uninit_phi_opnds_in_unrealizable_paths ( + phi_arg_def, uninit_opnds_arg_phi, + flag_arg_def, boundary_cst, cmp_code, + visited_phis, visited_flag_phis)) + return false; + + bitmap_clear_bit (*visited_flag_phis, + SSA_NAME_VERSION (gimple_phi_result (flag_arg_def))); + continue; + } + + /* Now check if the constant is in the guarded range. */ + if (is_value_included_in (flag_arg, boundary_cst, cmp_code)) + { + tree opnd; + gimple opnd_def; + + /* Now that we know that this undefined edge is not + pruned. If the operand is defined by another phi, + we can further prune the incoming edges of that + phi by checking the predicates of this operands. */ + + opnd = gimple_phi_arg_def (phi, i); + opnd_def = SSA_NAME_DEF_STMT (opnd); + if (gimple_code (opnd_def) == GIMPLE_PHI) + { + edge opnd_edge; + unsigned uninit_opnds2 + = compute_uninit_opnds_pos (opnd_def); + gcc_assert (!MASK_EMPTY (uninit_opnds2)); + opnd_edge = gimple_phi_arg_edge (phi, i); + if (!is_use_properly_guarded (phi, + opnd_edge->src, + opnd_def, + uninit_opnds2, + visited_phis)) + return false; + } + else + return false; + } + } + + return true; +} + /* A helper function that determines if the predicate set of the use is not overlapping with that of the uninit paths. The most common senario of guarded use is in Example 1: @@ -849,6 +1005,8 @@ bool swap_cond = false; bool invert = false; VEC(use_pred_info_t, heap) *the_pred_chain; + bitmap visited_flag_phis = NULL; + bool all_pruned = false; gcc_assert (num_preds > 0); /* Find within the common prefix of multiple predicate chains @@ -911,50 +1069,18 @@ if (cmp_code == ERROR_MARK) return false; - for (i = 0; i < sizeof (unsigned); i++) - { - tree flag_arg; - - if (!MASK_TEST_BIT (uninit_opnds, i)) - continue; - - flag_arg = gimple_phi_arg_def (flag_def, i); - if (!is_gimple_constant (flag_arg)) - return false; - - /* Now check if the constant is in the guarded range. */ - if (is_value_included_in (flag_arg, boundary_cst, cmp_code)) - { - tree opnd; - gimple opnd_def; - - /* Now that we know that this undefined edge is not - pruned. If the operand is defined by another phi, - we can further prune the incoming edges of that - phi by checking the predicates of this operands. */ + all_pruned = prune_uninit_phi_opnds_in_unrealizable_paths (phi, + uninit_opnds, + flag_def, + boundary_cst, + cmp_code, + visited_phis, + &visited_flag_phis); - opnd = gimple_phi_arg_def (phi, i); - opnd_def = SSA_NAME_DEF_STMT (opnd); - if (gimple_code (opnd_def) == GIMPLE_PHI) - { - edge opnd_edge; - unsigned uninit_opnds2 - = compute_uninit_opnds_pos (opnd_def); - gcc_assert (!MASK_EMPTY (uninit_opnds2)); - opnd_edge = gimple_phi_arg_edge (phi, i); - if (!is_use_properly_guarded (phi, - opnd_edge->src, - opnd_def, - uninit_opnds2, - visited_phis)) - return false; - } - else - return false; - } - } + if (visited_flag_phis) + BITMAP_FREE (visited_flag_phis); - return true; + return all_pruned; } /* Returns true if TC is AND or OR */ @@ -1525,7 +1651,7 @@ if (dump_file) dump_predicates (use_stmt, num_preds, preds, - "Use in stmt "); + "\nUse in stmt "); has_valid_preds = find_def_preds (&def_preds, &num_def_preds, phi); @@ -1577,27 +1703,17 @@ struct pointer_set_t *visited_phis; basic_block use_bb; - use_stmt = use_p->loc.stmt; + use_stmt = USE_STMT (use_p); + if (is_gimple_debug (use_stmt)) + continue; visited_phis = pointer_set_create (); - use_bb = gimple_bb (use_stmt); if (gimple_code (use_stmt) == GIMPLE_PHI) - { - unsigned i, n; - n = gimple_phi_num_args (use_stmt); - - /* Find the matching phi argument of the use. */ - for (i = 0; i < n; ++i) - { - if (gimple_phi_arg_def_ptr (use_stmt, i) == use_p->use) - { - edge e = gimple_phi_arg_edge (use_stmt, i); - use_bb = e->src; - break; - } - } - } + use_bb = gimple_phi_arg_edge (use_stmt, + PHI_ARG_INDEX_FROM_USE (use_p))->src; + else + use_bb = gimple_bb (use_stmt); if (is_use_properly_guarded (use_stmt, use_bb, @@ -1610,15 +1726,26 @@ } pointer_set_destroy (visited_phis); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "[CHECK]: Found unguarded use: "); + print_gimple_stmt (dump_file, use_stmt, 0, 0); + } /* Found one real use, return. */ if (gimple_code (use_stmt) != GIMPLE_PHI) - return use_stmt; + return use_stmt; /* Found a phi use that is not guarded, add the phi to the worklist. */ if (!pointer_set_insert (added_to_worklist, use_stmt)) { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "[WORKLIST]: Update worklist with phi: "); + print_gimple_stmt (dump_file, use_stmt, 0, 0); + } + VEC_safe_push (gimple, heap, *worklist, use_stmt); pointer_set_insert (possibly_undefined_names, phi_result); @@ -1653,6 +1780,12 @@ if (MASK_EMPTY (uninit_opnds)) return; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "[CHECK]: examining phi: "); + print_gimple_stmt (dump_file, phi, 0, 0); + } + /* Now check if we have any use of the value without proper guard. */ uninit_use_stmt = find_uninit_use (phi, uninit_opnds, worklist, added_to_worklist); @@ -1712,6 +1845,11 @@ { VEC_safe_push (gimple, heap, worklist, phi); pointer_set_insert (added_to_worklist, phi); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "[WORKLIST]: add to initial list: "); + print_gimple_stmt (dump_file, phi, 0, 0); + } break; } } @@ -1723,7 +1861,7 @@ cur_phi = VEC_pop (gimple, worklist); warn_uninitialized_phi (cur_phi, &worklist, added_to_worklist); } - + VEC_free (gimple, heap, worklist); pointer_set_destroy (added_to_worklist); pointer_set_destroy (possibly_undefined_names);