diff options
Diffstat (limited to 'gcc-4.8.1/gcc/tree-ssa-uninit.c')
-rw-r--r-- | gcc-4.8.1/gcc/tree-ssa-uninit.c | 2058 |
1 files changed, 0 insertions, 2058 deletions
diff --git a/gcc-4.8.1/gcc/tree-ssa-uninit.c b/gcc-4.8.1/gcc/tree-ssa-uninit.c deleted file mode 100644 index 2c47fe90b..000000000 --- a/gcc-4.8.1/gcc/tree-ssa-uninit.c +++ /dev/null @@ -1,2058 +0,0 @@ -/* Predicate aware uninitialized variable warning. - Copyright (C) 2001-2013 Free Software Foundation, Inc. - Contributed by Xinliang David Li <davidxl@google.com> - -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 "tm.h" -#include "tree.h" -#include "flags.h" -#include "tm_p.h" -#include "basic-block.h" -#include "function.h" -#include "gimple-pretty-print.h" -#include "bitmap.h" -#include "pointer-set.h" -#include "tree-flow.h" -#include "gimple.h" -#include "tree-inline.h" -#include "hashtab.h" -#include "tree-pass.h" -#include "diagnostic-core.h" - -/* This implements the pass that does predicate aware warning on uses of - possibly uninitialized variables. The pass first collects the set of - possibly uninitialized SSA names. For each such name, it walks through - all its immediate uses. For each immediate use, it rebuilds the condition - expression (the predicate) that guards the use. The predicate is then - examined to see if the variable is always defined under that same condition. - This is done either by pruning the unrealizable paths that lead to the - default definitions or by checking if the predicate set that guards the - defining paths is a superset of the use predicate. */ - - -/* Pointer set of potentially undefined ssa names, i.e., - ssa names that are defined by phi with operands that - are not defined or potentially undefined. */ -static struct pointer_set_t *possibly_undefined_names = 0; - -/* Bit mask handling macros. */ -#define MASK_SET_BIT(mask, pos) mask |= (1 << pos) -#define MASK_TEST_BIT(mask, pos) (mask & (1 << pos)) -#define MASK_EMPTY(mask) (mask == 0) - -/* Returns the first bit position (starting from LSB) - in mask that is non zero. Returns -1 if the mask is empty. */ -static int -get_mask_first_set_bit (unsigned mask) -{ - int pos = 0; - if (mask == 0) - return -1; - - while ((mask & (1 << pos)) == 0) - pos++; - - return pos; -} -#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) -{ - 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)) - || (possibly_undefined_names - && pointer_set_contains (possibly_undefined_names, t))); -} - -/* Like ssa_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)) - return false; - if (SSA_NAME_VAR (t) && TREE_NO_WARNING (SSA_NAME_VAR (t))) - return false; - return true; -} - -/* 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, - returns true to skip this this operand as being - redundant. Can be enhanced to be more general. */ - -static bool -can_skip_redundant_opnd (tree opnd, gimple phi) -{ - gimple op_def; - tree phi_def; - int i, n; - - phi_def = gimple_phi_result (phi); - op_def = SSA_NAME_DEF_STMT (opnd); - if (gimple_code (op_def) != GIMPLE_PHI) - return false; - n = gimple_phi_num_args (op_def); - for (i = 0; i < n; ++i) - { - tree op = gimple_phi_arg_def (op_def, i); - if (TREE_CODE (op) != SSA_NAME) - continue; - if (op != phi_def && uninit_undefined_value_p (op)) - return false; - } - - return true; -} - -/* Returns a bit mask holding the positions of arguments in PHI - that have empty (or possibly empty) definitions. */ - -static unsigned -compute_uninit_opnds_pos (gimple phi) -{ - size_t i, n; - 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) - { - tree op = gimple_phi_arg_def (phi, i); - if (TREE_CODE (op) == SSA_NAME - && uninit_undefined_value_p (op) - && !can_skip_redundant_opnd (op, phi)) - MASK_SET_BIT (uninit_opnds, i); - } - return uninit_opnds; -} - -/* Find the immediate postdominator PDOM of the specified - basic block BLOCK. */ - -static inline basic_block -find_pdom (basic_block block) -{ - if (block == EXIT_BLOCK_PTR) - return EXIT_BLOCK_PTR; - else - { - basic_block bb - = get_immediate_dominator (CDI_POST_DOMINATORS, block); - if (! bb) - return EXIT_BLOCK_PTR; - return bb; - } -} - -/* Find the immediate DOM of the specified - basic block BLOCK. */ - -static inline basic_block -find_dom (basic_block block) -{ - if (block == ENTRY_BLOCK_PTR) - return ENTRY_BLOCK_PTR; - else - { - basic_block bb = get_immediate_dominator (CDI_DOMINATORS, block); - if (! bb) - return ENTRY_BLOCK_PTR; - return bb; - } -} - -/* Returns true if BB1 is postdominating BB2 and BB1 is - not a loop exit bb. The loop exit bb check is simple and does - not cover all cases. */ - -static bool -is_non_loop_exit_postdominating (basic_block bb1, basic_block bb2) -{ - if (!dominated_by_p (CDI_POST_DOMINATORS, bb2, bb1)) - return false; - - if (single_pred_p (bb1) && !single_succ_p (bb2)) - return false; - - return true; -} - -/* Find the closest postdominator of a specified BB, which is control - equivalent to BB. */ - -static inline basic_block -find_control_equiv_block (basic_block bb) -{ - basic_block pdom; - - pdom = find_pdom (bb); - - /* Skip the postdominating bb that is also loop exit. */ - if (!is_non_loop_exit_postdominating (pdom, bb)) - return NULL; - - if (dominated_by_p (CDI_DOMINATORS, pdom, bb)) - return pdom; - - return NULL; -} - -#define MAX_NUM_CHAINS 8 -#define MAX_CHAIN_LEN 5 -#define MAX_POSTDOM_CHECK 8 - -/* Computes the control dependence chains (paths of edges) - for DEP_BB up to the dominating basic block BB (the head node of a - chain should be dominated by it). CD_CHAINS is pointer to a - dynamic array holding the result chains. CUR_CD_CHAIN is the current - chain being computed. *NUM_CHAINS is total number of chains. The - function returns true if the information is successfully computed, - return false if there is no control dependence or not computed. */ - -static bool -compute_control_dep_chain (basic_block bb, basic_block dep_bb, - vec<edge> *cd_chains, - size_t *num_chains, - vec<edge> *cur_cd_chain) -{ - edge_iterator ei; - edge e; - size_t i; - bool found_cd_chain = false; - size_t cur_chain_len = 0; - - if (EDGE_COUNT (bb->succs) < 2) - return false; - - /* Could use a set instead. */ - cur_chain_len = cur_cd_chain->length (); - if (cur_chain_len > MAX_CHAIN_LEN) - return false; - - for (i = 0; i < cur_chain_len; i++) - { - edge e = (*cur_cd_chain)[i]; - /* cycle detected. */ - if (e->src == bb) - return false; - } - - FOR_EACH_EDGE (e, ei, bb->succs) - { - basic_block cd_bb; - int post_dom_check = 0; - if (e->flags & (EDGE_FAKE | EDGE_ABNORMAL)) - continue; - - cd_bb = e->dest; - cur_cd_chain->safe_push (e); - while (!is_non_loop_exit_postdominating (cd_bb, bb)) - { - if (cd_bb == dep_bb) - { - /* Found a direct control dependence. */ - if (*num_chains < MAX_NUM_CHAINS) - { - cd_chains[*num_chains] = cur_cd_chain->copy (); - (*num_chains)++; - } - found_cd_chain = true; - /* check path from next edge. */ - break; - } - - /* Now check if DEP_BB is indirectly control dependent on BB. */ - if (compute_control_dep_chain (cd_bb, dep_bb, cd_chains, - num_chains, cur_cd_chain)) - { - found_cd_chain = true; - break; - } - - cd_bb = find_pdom (cd_bb); - post_dom_check++; - if (cd_bb == EXIT_BLOCK_PTR || post_dom_check > MAX_POSTDOM_CHECK) - break; - } - cur_cd_chain->pop (); - gcc_assert (cur_cd_chain->length () == cur_chain_len); - } - gcc_assert (cur_cd_chain->length () == cur_chain_len); - - return found_cd_chain; -} - -typedef struct use_pred_info -{ - gimple cond; - bool invert; -} *use_pred_info_t; - - - -/* Converts the chains of control dependence edges into a set of - predicates. A control dependence chain is represented by a vector - edges. DEP_CHAINS points to an array of dependence chains. - NUM_CHAINS is the size of the chain array. One edge in a dependence - chain is mapped to predicate expression represented by use_pred_info_t - type. One dependence chain is converted to a composite predicate that - is the result of AND operation of use_pred_info_t mapped to each edge. - A composite predicate is presented by a vector of use_pred_info_t. On - return, *PREDS points to the resulting array of composite predicates. - *NUM_PREDS is the number of composite predictes. */ - -static bool -convert_control_dep_chain_into_preds (vec<edge> *dep_chains, - size_t num_chains, - vec<use_pred_info_t> **preds, - size_t *num_preds) -{ - bool has_valid_pred = false; - size_t i, j; - if (num_chains == 0 || num_chains >= MAX_NUM_CHAINS) - return false; - - /* Now convert the control dep chain into a set - of predicates. */ - typedef vec<use_pred_info_t> vec_use_pred_info_t_heap; - *preds = XCNEWVEC (vec_use_pred_info_t_heap, num_chains); - *num_preds = num_chains; - - for (i = 0; i < num_chains; i++) - { - vec<edge> one_cd_chain = dep_chains[i]; - - has_valid_pred = false; - for (j = 0; j < one_cd_chain.length (); j++) - { - gimple cond_stmt; - gimple_stmt_iterator gsi; - basic_block guard_bb; - use_pred_info_t one_pred; - edge e; - - e = one_cd_chain[j]; - guard_bb = e->src; - gsi = gsi_last_bb (guard_bb); - if (gsi_end_p (gsi)) - { - has_valid_pred = false; - break; - } - cond_stmt = gsi_stmt (gsi); - if (gimple_code (cond_stmt) == GIMPLE_CALL - && EDGE_COUNT (e->src->succs) >= 2) - { - /* Ignore EH edge. Can add assertion - on the other edge's flag. */ - continue; - } - /* Skip if there is essentially one succesor. */ - if (EDGE_COUNT (e->src->succs) == 2) - { - edge e1; - edge_iterator ei1; - bool skip = false; - - FOR_EACH_EDGE (e1, ei1, e->src->succs) - { - if (EDGE_COUNT (e1->dest->succs) == 0) - { - skip = true; - break; - } - } - if (skip) - continue; - } - if (gimple_code (cond_stmt) != GIMPLE_COND) - { - has_valid_pred = false; - break; - } - one_pred = XNEW (struct use_pred_info); - one_pred->cond = cond_stmt; - one_pred->invert = !!(e->flags & EDGE_FALSE_VALUE); - (*preds)[i].safe_push (one_pred); - has_valid_pred = true; - } - - if (!has_valid_pred) - break; - } - return has_valid_pred; -} - -/* Computes all control dependence chains for USE_BB. The control - dependence chains are then converted to an array of composite - predicates pointed to by PREDS. PHI_BB is the basic block of - the phi whose result is used in USE_BB. */ - -static bool -find_predicates (vec<use_pred_info_t> **preds, - size_t *num_preds, - basic_block phi_bb, - basic_block use_bb) -{ - size_t num_chains = 0, i; - vec<edge> *dep_chains = 0; - vec<edge> cur_chain = vNULL; - bool has_valid_pred = false; - basic_block cd_root = 0; - - typedef vec<edge> vec_edge_heap; - dep_chains = XCNEWVEC (vec_edge_heap, MAX_NUM_CHAINS); - - /* First find the closest bb that is control equivalent to PHI_BB - that also dominates USE_BB. */ - cd_root = phi_bb; - while (dominated_by_p (CDI_DOMINATORS, use_bb, cd_root)) - { - basic_block ctrl_eq_bb = find_control_equiv_block (cd_root); - if (ctrl_eq_bb && dominated_by_p (CDI_DOMINATORS, use_bb, ctrl_eq_bb)) - cd_root = ctrl_eq_bb; - else - break; - } - - compute_control_dep_chain (cd_root, use_bb, - dep_chains, &num_chains, - &cur_chain); - - has_valid_pred - = convert_control_dep_chain_into_preds (dep_chains, - num_chains, - preds, - num_preds); - /* Free individual chain */ - cur_chain.release (); - for (i = 0; i < num_chains; i++) - dep_chains[i].release (); - free (dep_chains); - return has_valid_pred; -} - -/* Computes the set of incoming edges of PHI that have non empty - definitions of a phi chain. The collection will be done - recursively on operands that are defined by phis. CD_ROOT - is the control dependence root. *EDGES holds the result, and - VISITED_PHIS is a pointer set for detecting cycles. */ - -static void -collect_phi_def_edges (gimple phi, basic_block cd_root, - vec<edge> *edges, - struct pointer_set_t *visited_phis) -{ - size_t i, n; - edge opnd_edge; - tree opnd; - - if (pointer_set_insert (visited_phis, phi)) - return; - - n = gimple_phi_num_args (phi); - for (i = 0; i < n; i++) - { - opnd_edge = gimple_phi_arg_edge (phi, i); - opnd = gimple_phi_arg_def (phi, i); - - 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); - } - edges->safe_push (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 (!uninit_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); - } - edges->safe_push (opnd_edge); - } - } - } -} - -/* For each use edge of PHI, computes all control dependence chains. - The control dependence chains are then converted to an array of - composite predicates pointed to by PREDS. */ - -static bool -find_def_preds (vec<use_pred_info_t> **preds, - size_t *num_preds, gimple phi) -{ - size_t num_chains = 0, i, n; - vec<edge> *dep_chains = 0; - vec<edge> cur_chain = vNULL; - vec<edge> def_edges = vNULL; - bool has_valid_pred = false; - basic_block phi_bb, cd_root = 0; - struct pointer_set_t *visited_phis; - - typedef vec<edge> vec_edge_heap; - dep_chains = XCNEWVEC (vec_edge_heap, MAX_NUM_CHAINS); - - phi_bb = gimple_bb (phi); - /* First find the closest dominating bb to be - the control dependence root */ - cd_root = find_dom (phi_bb); - if (!cd_root) - return false; - - visited_phis = pointer_set_create (); - collect_phi_def_edges (phi, cd_root, &def_edges, visited_phis); - pointer_set_destroy (visited_phis); - - n = def_edges.length (); - if (n == 0) - return false; - - for (i = 0; i < n; i++) - { - size_t prev_nc, j; - edge opnd_edge; - - opnd_edge = def_edges[i]; - prev_nc = num_chains; - compute_control_dep_chain (cd_root, opnd_edge->src, - dep_chains, &num_chains, - &cur_chain); - /* Free individual chain */ - cur_chain.release (); - - /* Now update the newly added chains with - the phi operand edge: */ - if (EDGE_COUNT (opnd_edge->src->succs) > 1) - { - if (prev_nc == num_chains - && num_chains < MAX_NUM_CHAINS) - num_chains++; - for (j = prev_nc; j < num_chains; j++) - { - dep_chains[j].safe_push (opnd_edge); - } - } - } - - has_valid_pred - = convert_control_dep_chain_into_preds (dep_chains, - num_chains, - preds, - num_preds); - for (i = 0; i < num_chains; i++) - dep_chains[i].release (); - free (dep_chains); - return has_valid_pred; -} - -/* Dumps the predicates (PREDS) for USESTMT. */ - -static void -dump_predicates (gimple usestmt, size_t num_preds, - vec<use_pred_info_t> *preds, - const char* msg) -{ - size_t i, j; - vec<use_pred_info_t> one_pred_chain; - fprintf (dump_file, msg); - print_gimple_stmt (dump_file, usestmt, 0, 0); - fprintf (dump_file, "is guarded by :\n"); - /* do some dumping here: */ - for (i = 0; i < num_preds; i++) - { - size_t np; - - one_pred_chain = preds[i]; - np = one_pred_chain.length (); - - for (j = 0; j < np; j++) - { - use_pred_info_t one_pred - = one_pred_chain[j]; - if (one_pred->invert) - fprintf (dump_file, " (.NOT.) "); - print_gimple_stmt (dump_file, one_pred->cond, 0, 0); - if (j < np - 1) - fprintf (dump_file, "(.AND.)\n"); - } - if (i < num_preds - 1) - fprintf (dump_file, "(.OR.)\n"); - } -} - -/* Destroys the predicate set *PREDS. */ - -static void -destroy_predicate_vecs (size_t n, - vec<use_pred_info_t> * preds) -{ - size_t i, j; - for (i = 0; i < n; i++) - { - for (j = 0; j < preds[i].length (); j++) - free (preds[i][j]); - preds[i].release (); - } - free (preds); -} - - -/* Computes the 'normalized' conditional code with operand - swapping and condition inversion. */ - -static enum tree_code -get_cmp_code (enum tree_code orig_cmp_code, - bool swap_cond, bool invert) -{ - enum tree_code tc = orig_cmp_code; - - if (swap_cond) - tc = swap_tree_comparison (orig_cmp_code); - if (invert) - tc = invert_tree_comparison (tc, false); - - switch (tc) - { - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - break; - default: - return ERROR_MARK; - } - return tc; -} - -/* Returns true if VAL falls in the range defined by BOUNDARY and CMPC, i.e. - all values in the range satisfies (x CMPC BOUNDARY) == true. */ - -static bool -is_value_included_in (tree val, tree boundary, enum tree_code cmpc) -{ - bool inverted = false; - bool is_unsigned; - bool result; - - /* Only handle integer constant here. */ - if (TREE_CODE (val) != INTEGER_CST - || TREE_CODE (boundary) != INTEGER_CST) - return true; - - is_unsigned = TYPE_UNSIGNED (TREE_TYPE (val)); - - if (cmpc == GE_EXPR || cmpc == GT_EXPR - || cmpc == NE_EXPR) - { - cmpc = invert_tree_comparison (cmpc, false); - inverted = true; - } - - if (is_unsigned) - { - if (cmpc == EQ_EXPR) - result = tree_int_cst_equal (val, boundary); - else if (cmpc == LT_EXPR) - result = INT_CST_LT_UNSIGNED (val, boundary); - else - { - gcc_assert (cmpc == LE_EXPR); - result = (tree_int_cst_equal (val, boundary) - || INT_CST_LT_UNSIGNED (val, boundary)); - } - } - else - { - if (cmpc == EQ_EXPR) - result = tree_int_cst_equal (val, boundary); - else if (cmpc == LT_EXPR) - result = INT_CST_LT (val, boundary); - else - { - gcc_assert (cmpc == LE_EXPR); - result = (tree_int_cst_equal (val, boundary) - || INT_CST_LT (val, boundary)); - } - } - - if (inverted) - result ^= 1; - - return result; -} - -/* Returns true if PRED is common among all the predicate - chains (PREDS) (and therefore can be factored out). - NUM_PRED_CHAIN is the size of array PREDS. */ - -static bool -find_matching_predicate_in_rest_chains (use_pred_info_t pred, - vec<use_pred_info_t> *preds, - size_t num_pred_chains) -{ - size_t i, j, n; - - /* trival case */ - if (num_pred_chains == 1) - return true; - - for (i = 1; i < num_pred_chains; i++) - { - bool found = false; - vec<use_pred_info_t> one_chain = preds[i]; - n = one_chain.length (); - for (j = 0; j < n; j++) - { - use_pred_info_t pred2 - = one_chain[j]; - /* can relax the condition comparison to not - use address comparison. However, the most common - case is that multiple control dependent paths share - a common path prefix, so address comparison should - be ok. */ - - if (pred2->cond == pred->cond - && pred2->invert == pred->invert) - { - found = true; - break; - } - } - if (!found) - return false; - } - return true; -} - -/* Forward declaration. */ -static bool -is_use_properly_guarded (gimple use_stmt, - basic_block use_bb, - gimple phi, - 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: - Example 1: - if (some_cond) - { - x = ...; - flag = true; - } - - ... some code ... - - if (flag) - use (x); - - The real world examples are usually more complicated, but similar - and usually result from inlining: - - bool init_func (int * x) - { - if (some_cond) - return false; - *x = .. - return true; - } - - void foo(..) - { - int x; - - if (!init_func(&x)) - return; - - .. some_code ... - use (x); - } - - Another possible use scenario is in the following trivial example: - - Example 2: - if (n > 0) - x = 1; - ... - if (n > 0) - { - if (m < 2) - .. = x; - } - - Predicate analysis needs to compute the composite predicate: - - 1) 'x' use predicate: (n > 0) .AND. (m < 2) - 2) 'x' default value (non-def) predicate: .NOT. (n > 0) - (the predicate chain for phi operand defs can be computed - starting from a bb that is control equivalent to the phi's - bb and is dominating the operand def.) - - and check overlapping: - (n > 0) .AND. (m < 2) .AND. (.NOT. (n > 0)) - <==> false - - This implementation provides framework that can handle - scenarios. (Note that many simple cases are handled properly - without the predicate analysis -- this is due to jump threading - transformation which eliminates the merge point thus makes - path sensitive analysis unnecessary.) - - NUM_PREDS is the number is the number predicate chains, PREDS is - the array of chains, PHI is the phi node whose incoming (undefined) - paths need to be pruned, and UNINIT_OPNDS is the bitmap holding - uninit operand positions. VISITED_PHIS is the pointer set of phi - stmts being checked. */ - - -static bool -use_pred_not_overlap_with_undef_path_pred ( - size_t num_preds, - vec<use_pred_info_t> *preds, - gimple phi, unsigned uninit_opnds, - struct pointer_set_t *visited_phis) -{ - unsigned int i, n; - gimple flag_def = 0; - tree boundary_cst = 0; - enum tree_code cmp_code; - bool swap_cond = false; - bool invert = false; - vec<use_pred_info_t> 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 - a predicate that is a comparison of a flag variable against - a constant. */ - the_pred_chain = preds[0]; - n = the_pred_chain.length (); - for (i = 0; i < n; i++) - { - gimple cond; - tree cond_lhs, cond_rhs, flag = 0; - - use_pred_info_t the_pred - = the_pred_chain[i]; - - cond = the_pred->cond; - invert = the_pred->invert; - cond_lhs = gimple_cond_lhs (cond); - cond_rhs = gimple_cond_rhs (cond); - cmp_code = gimple_cond_code (cond); - - if (cond_lhs != NULL_TREE && TREE_CODE (cond_lhs) == SSA_NAME - && cond_rhs != NULL_TREE && is_gimple_constant (cond_rhs)) - { - boundary_cst = cond_rhs; - flag = cond_lhs; - } - else if (cond_rhs != NULL_TREE && TREE_CODE (cond_rhs) == SSA_NAME - && cond_lhs != NULL_TREE && is_gimple_constant (cond_lhs)) - { - boundary_cst = cond_lhs; - flag = cond_rhs; - swap_cond = true; - } - - if (!flag) - continue; - - flag_def = SSA_NAME_DEF_STMT (flag); - - if (!flag_def) - continue; - - if ((gimple_code (flag_def) == GIMPLE_PHI) - && (gimple_bb (flag_def) == gimple_bb (phi)) - && find_matching_predicate_in_rest_chains ( - the_pred, preds, num_preds)) - break; - - flag_def = 0; - } - - if (!flag_def) - return false; - - /* Now check all the uninit incoming edge has a constant flag value - that is in conflict with the use guard/predicate. */ - cmp_code = get_cmp_code (cmp_code, swap_cond, invert); - - if (cmp_code == ERROR_MARK) - return false; - - all_pruned = prune_uninit_phi_opnds_in_unrealizable_paths (phi, - uninit_opnds, - flag_def, - boundary_cst, - cmp_code, - visited_phis, - &visited_flag_phis); - - if (visited_flag_phis) - BITMAP_FREE (visited_flag_phis); - - return all_pruned; -} - -/* Returns true if TC is AND or OR */ - -static inline bool -is_and_or_or (enum tree_code tc, tree typ) -{ - return (tc == BIT_IOR_EXPR - || (tc == BIT_AND_EXPR - && (typ == 0 || TREE_CODE (typ) == BOOLEAN_TYPE))); -} - -typedef struct norm_cond -{ - vec<gimple> conds; - enum tree_code cond_code; - bool invert; -} *norm_cond_t; - - -/* Normalizes gimple condition COND. The normalization follows - UD chains to form larger condition expression trees. NORM_COND - holds the normalized result. COND_CODE is the logical opcode - (AND or OR) of the normalized tree. */ - -static void -normalize_cond_1 (gimple cond, - norm_cond_t norm_cond, - enum tree_code cond_code) -{ - enum gimple_code gc; - enum tree_code cur_cond_code; - tree rhs1, rhs2; - - gc = gimple_code (cond); - if (gc != GIMPLE_ASSIGN) - { - norm_cond->conds.safe_push (cond); - return; - } - - cur_cond_code = gimple_assign_rhs_code (cond); - rhs1 = gimple_assign_rhs1 (cond); - rhs2 = gimple_assign_rhs2 (cond); - if (cur_cond_code == NE_EXPR) - { - if (integer_zerop (rhs2) - && (TREE_CODE (rhs1) == SSA_NAME)) - normalize_cond_1 ( - SSA_NAME_DEF_STMT (rhs1), - norm_cond, cond_code); - else if (integer_zerop (rhs1) - && (TREE_CODE (rhs2) == SSA_NAME)) - normalize_cond_1 ( - SSA_NAME_DEF_STMT (rhs2), - norm_cond, cond_code); - else - norm_cond->conds.safe_push (cond); - - return; - } - - if (is_and_or_or (cur_cond_code, TREE_TYPE (rhs1)) - && (cond_code == cur_cond_code || cond_code == ERROR_MARK) - && (TREE_CODE (rhs1) == SSA_NAME && TREE_CODE (rhs2) == SSA_NAME)) - { - normalize_cond_1 (SSA_NAME_DEF_STMT (rhs1), - norm_cond, cur_cond_code); - normalize_cond_1 (SSA_NAME_DEF_STMT (rhs2), - norm_cond, cur_cond_code); - norm_cond->cond_code = cur_cond_code; - } - else - norm_cond->conds.safe_push (cond); -} - -/* See normalize_cond_1 for details. INVERT is a flag to indicate - if COND needs to be inverted or not. */ - -static void -normalize_cond (gimple cond, norm_cond_t norm_cond, bool invert) -{ - enum tree_code cond_code; - - norm_cond->cond_code = ERROR_MARK; - norm_cond->invert = false; - norm_cond->conds.create (0); - gcc_assert (gimple_code (cond) == GIMPLE_COND); - cond_code = gimple_cond_code (cond); - if (invert) - cond_code = invert_tree_comparison (cond_code, false); - - if (cond_code == NE_EXPR) - { - if (integer_zerop (gimple_cond_rhs (cond)) - && (TREE_CODE (gimple_cond_lhs (cond)) == SSA_NAME)) - normalize_cond_1 ( - SSA_NAME_DEF_STMT (gimple_cond_lhs (cond)), - norm_cond, ERROR_MARK); - else if (integer_zerop (gimple_cond_lhs (cond)) - && (TREE_CODE (gimple_cond_rhs (cond)) == SSA_NAME)) - normalize_cond_1 ( - SSA_NAME_DEF_STMT (gimple_cond_rhs (cond)), - norm_cond, ERROR_MARK); - else - { - norm_cond->conds.safe_push (cond); - norm_cond->invert = invert; - } - } - else - { - norm_cond->conds.safe_push (cond); - norm_cond->invert = invert; - } - - gcc_assert (norm_cond->conds.length () == 1 - || is_and_or_or (norm_cond->cond_code, NULL)); -} - -/* Returns true if the domain for condition COND1 is a subset of - COND2. REVERSE is a flag. when it is true the function checks - if COND1 is a superset of COND2. INVERT1 and INVERT2 are flags - to indicate if COND1 and COND2 need to be inverted or not. */ - -static bool -is_gcond_subset_of (gimple cond1, bool invert1, - gimple cond2, bool invert2, - bool reverse) -{ - enum gimple_code gc1, gc2; - enum tree_code cond1_code, cond2_code; - gimple tmp; - tree cond1_lhs, cond1_rhs, cond2_lhs, cond2_rhs; - - /* Take the short cut. */ - if (cond1 == cond2) - return true; - - if (reverse) - { - tmp = cond1; - cond1 = cond2; - cond2 = tmp; - } - - gc1 = gimple_code (cond1); - gc2 = gimple_code (cond2); - - if ((gc1 != GIMPLE_ASSIGN && gc1 != GIMPLE_COND) - || (gc2 != GIMPLE_ASSIGN && gc2 != GIMPLE_COND)) - return cond1 == cond2; - - cond1_code = ((gc1 == GIMPLE_ASSIGN) - ? gimple_assign_rhs_code (cond1) - : gimple_cond_code (cond1)); - - cond2_code = ((gc2 == GIMPLE_ASSIGN) - ? gimple_assign_rhs_code (cond2) - : gimple_cond_code (cond2)); - - if (TREE_CODE_CLASS (cond1_code) != tcc_comparison - || TREE_CODE_CLASS (cond2_code) != tcc_comparison) - return false; - - if (invert1) - cond1_code = invert_tree_comparison (cond1_code, false); - if (invert2) - cond2_code = invert_tree_comparison (cond2_code, false); - - cond1_lhs = ((gc1 == GIMPLE_ASSIGN) - ? gimple_assign_rhs1 (cond1) - : gimple_cond_lhs (cond1)); - cond1_rhs = ((gc1 == GIMPLE_ASSIGN) - ? gimple_assign_rhs2 (cond1) - : gimple_cond_rhs (cond1)); - cond2_lhs = ((gc2 == GIMPLE_ASSIGN) - ? gimple_assign_rhs1 (cond2) - : gimple_cond_lhs (cond2)); - cond2_rhs = ((gc2 == GIMPLE_ASSIGN) - ? gimple_assign_rhs2 (cond2) - : gimple_cond_rhs (cond2)); - - /* Assuming const operands have been swapped to the - rhs at this point of the analysis. */ - - if (cond1_lhs != cond2_lhs) - return false; - - if (!is_gimple_constant (cond1_rhs) - || TREE_CODE (cond1_rhs) != INTEGER_CST) - return (cond1_rhs == cond2_rhs); - - if (!is_gimple_constant (cond2_rhs) - || TREE_CODE (cond2_rhs) != INTEGER_CST) - return (cond1_rhs == cond2_rhs); - - if (cond1_code == EQ_EXPR) - return is_value_included_in (cond1_rhs, - cond2_rhs, cond2_code); - if (cond1_code == NE_EXPR || cond2_code == EQ_EXPR) - return ((cond2_code == cond1_code) - && tree_int_cst_equal (cond1_rhs, cond2_rhs)); - - if (((cond1_code == GE_EXPR || cond1_code == GT_EXPR) - && (cond2_code == LE_EXPR || cond2_code == LT_EXPR)) - || ((cond1_code == LE_EXPR || cond1_code == LT_EXPR) - && (cond2_code == GE_EXPR || cond2_code == GT_EXPR))) - return false; - - if (cond1_code != GE_EXPR && cond1_code != GT_EXPR - && cond1_code != LE_EXPR && cond1_code != LT_EXPR) - return false; - - if (cond1_code == GT_EXPR) - { - cond1_code = GE_EXPR; - cond1_rhs = fold_binary (PLUS_EXPR, TREE_TYPE (cond1_rhs), - cond1_rhs, - fold_convert (TREE_TYPE (cond1_rhs), - integer_one_node)); - } - else if (cond1_code == LT_EXPR) - { - cond1_code = LE_EXPR; - cond1_rhs = fold_binary (MINUS_EXPR, TREE_TYPE (cond1_rhs), - cond1_rhs, - fold_convert (TREE_TYPE (cond1_rhs), - integer_one_node)); - } - - if (!cond1_rhs) - return false; - - gcc_assert (cond1_code == GE_EXPR || cond1_code == LE_EXPR); - - if (cond2_code == GE_EXPR || cond2_code == GT_EXPR || - cond2_code == LE_EXPR || cond2_code == LT_EXPR) - return is_value_included_in (cond1_rhs, - cond2_rhs, cond2_code); - else if (cond2_code == NE_EXPR) - return - (is_value_included_in (cond1_rhs, - cond2_rhs, cond2_code) - && !is_value_included_in (cond2_rhs, - cond1_rhs, cond1_code)); - return false; -} - -/* Returns true if the domain of the condition expression - in COND is a subset of any of the sub-conditions - of the normalized condtion NORM_COND. INVERT is a flag - to indicate of the COND needs to be inverted. - REVERSE is a flag. When it is true, the check is reversed -- - it returns true if COND is a superset of any of the subconditions - of NORM_COND. */ - -static bool -is_subset_of_any (gimple cond, bool invert, - norm_cond_t norm_cond, bool reverse) -{ - size_t i; - size_t len = norm_cond->conds.length (); - - for (i = 0; i < len; i++) - { - if (is_gcond_subset_of (cond, invert, - norm_cond->conds[i], - false, reverse)) - return true; - } - return false; -} - -/* NORM_COND1 and NORM_COND2 are normalized logical/BIT OR - expressions (formed by following UD chains not control - dependence chains). The function returns true of domain - of and expression NORM_COND1 is a subset of NORM_COND2's. - The implementation is conservative, and it returns false if - it the inclusion relationship may not hold. */ - -static bool -is_or_set_subset_of (norm_cond_t norm_cond1, - norm_cond_t norm_cond2) -{ - size_t i; - size_t len = norm_cond1->conds.length (); - - for (i = 0; i < len; i++) - { - if (!is_subset_of_any (norm_cond1->conds[i], - false, norm_cond2, false)) - return false; - } - return true; -} - -/* NORM_COND1 and NORM_COND2 are normalized logical AND - expressions (formed by following UD chains not control - dependence chains). The function returns true of domain - of and expression NORM_COND1 is a subset of NORM_COND2's. */ - -static bool -is_and_set_subset_of (norm_cond_t norm_cond1, - norm_cond_t norm_cond2) -{ - size_t i; - size_t len = norm_cond2->conds.length (); - - for (i = 0; i < len; i++) - { - if (!is_subset_of_any (norm_cond2->conds[i], - false, norm_cond1, true)) - return false; - } - return true; -} - -/* Returns true of the domain if NORM_COND1 is a subset - of that of NORM_COND2. Returns false if it can not be - proved to be so. */ - -static bool -is_norm_cond_subset_of (norm_cond_t norm_cond1, - norm_cond_t norm_cond2) -{ - size_t i; - enum tree_code code1, code2; - - code1 = norm_cond1->cond_code; - code2 = norm_cond2->cond_code; - - if (code1 == BIT_AND_EXPR) - { - /* Both conditions are AND expressions. */ - if (code2 == BIT_AND_EXPR) - return is_and_set_subset_of (norm_cond1, norm_cond2); - /* NORM_COND1 is an AND expression, and NORM_COND2 is an OR - expression. In this case, returns true if any subexpression - of NORM_COND1 is a subset of any subexpression of NORM_COND2. */ - else if (code2 == BIT_IOR_EXPR) - { - size_t len1; - len1 = norm_cond1->conds.length (); - for (i = 0; i < len1; i++) - { - gimple cond1 = norm_cond1->conds[i]; - if (is_subset_of_any (cond1, false, norm_cond2, false)) - return true; - } - return false; - } - else - { - gcc_assert (code2 == ERROR_MARK); - gcc_assert (norm_cond2->conds.length () == 1); - return is_subset_of_any (norm_cond2->conds[0], - norm_cond2->invert, norm_cond1, true); - } - } - /* NORM_COND1 is an OR expression */ - else if (code1 == BIT_IOR_EXPR) - { - if (code2 != code1) - return false; - - return is_or_set_subset_of (norm_cond1, norm_cond2); - } - else - { - gcc_assert (code1 == ERROR_MARK); - gcc_assert (norm_cond1->conds.length () == 1); - /* Conservatively returns false if NORM_COND1 is non-decomposible - and NORM_COND2 is an AND expression. */ - if (code2 == BIT_AND_EXPR) - return false; - - if (code2 == BIT_IOR_EXPR) - return is_subset_of_any (norm_cond1->conds[0], - norm_cond1->invert, norm_cond2, false); - - gcc_assert (code2 == ERROR_MARK); - gcc_assert (norm_cond2->conds.length () == 1); - return is_gcond_subset_of (norm_cond1->conds[0], - norm_cond1->invert, - norm_cond2->conds[0], - norm_cond2->invert, false); - } -} - -/* Returns true of the domain of single predicate expression - EXPR1 is a subset of that of EXPR2. Returns false if it - can not be proved. */ - -static bool -is_pred_expr_subset_of (use_pred_info_t expr1, - use_pred_info_t expr2) -{ - gimple cond1, cond2; - enum tree_code code1, code2; - struct norm_cond norm_cond1, norm_cond2; - bool is_subset = false; - - cond1 = expr1->cond; - cond2 = expr2->cond; - code1 = gimple_cond_code (cond1); - code2 = gimple_cond_code (cond2); - - if (expr1->invert) - code1 = invert_tree_comparison (code1, false); - if (expr2->invert) - code2 = invert_tree_comparison (code2, false); - - /* Fast path -- match exactly */ - if ((gimple_cond_lhs (cond1) == gimple_cond_lhs (cond2)) - && (gimple_cond_rhs (cond1) == gimple_cond_rhs (cond2)) - && (code1 == code2)) - return true; - - /* Normalize conditions. To keep NE_EXPR, do not invert - with both need inversion. */ - normalize_cond (cond1, &norm_cond1, (expr1->invert)); - normalize_cond (cond2, &norm_cond2, (expr2->invert)); - - is_subset = is_norm_cond_subset_of (&norm_cond1, &norm_cond2); - - /* Free memory */ - norm_cond1.conds.release (); - norm_cond2.conds.release (); - return is_subset ; -} - -/* Returns true if the domain of PRED1 is a subset - of that of PRED2. Returns false if it can not be proved so. */ - -static bool -is_pred_chain_subset_of (vec<use_pred_info_t> pred1, - vec<use_pred_info_t> pred2) -{ - size_t np1, np2, i1, i2; - - np1 = pred1.length (); - np2 = pred2.length (); - - for (i2 = 0; i2 < np2; i2++) - { - bool found = false; - use_pred_info_t info2 - = pred2[i2]; - for (i1 = 0; i1 < np1; i1++) - { - use_pred_info_t info1 - = pred1[i1]; - if (is_pred_expr_subset_of (info1, info2)) - { - found = true; - break; - } - } - if (!found) - return false; - } - return true; -} - -/* Returns true if the domain defined by - one pred chain ONE_PRED is a subset of the domain - of *PREDS. It returns false if ONE_PRED's domain is - not a subset of any of the sub-domains of PREDS ( - corresponding to each individual chains in it), even - though it may be still be a subset of whole domain - of PREDS which is the union (ORed) of all its subdomains. - In other words, the result is conservative. */ - -static bool -is_included_in (vec<use_pred_info_t> one_pred, - vec<use_pred_info_t> *preds, - size_t n) -{ - size_t i; - - for (i = 0; i < n; i++) - { - if (is_pred_chain_subset_of (one_pred, preds[i])) - return true; - } - - return false; -} - -/* compares two predicate sets PREDS1 and PREDS2 and returns - true if the domain defined by PREDS1 is a superset - of PREDS2's domain. N1 and N2 are array sizes of PREDS1 and - PREDS2 respectively. The implementation chooses not to build - generic trees (and relying on the folding capability of the - compiler), but instead performs brute force comparison of - individual predicate chains (won't be a compile time problem - as the chains are pretty short). When the function returns - false, it does not necessarily mean *PREDS1 is not a superset - of *PREDS2, but mean it may not be so since the analysis can - not prove it. In such cases, false warnings may still be - emitted. */ - -static bool -is_superset_of (vec<use_pred_info_t> *preds1, - size_t n1, - vec<use_pred_info_t> *preds2, - size_t n2) -{ - size_t i; - vec<use_pred_info_t> one_pred_chain; - - for (i = 0; i < n2; i++) - { - one_pred_chain = preds2[i]; - if (!is_included_in (one_pred_chain, preds1, n1)) - return false; - } - - return true; -} - -/* Comparison function used by qsort. It is used to - sort predicate chains to allow predicate - simplification. */ - -static int -pred_chain_length_cmp (const void *p1, const void *p2) -{ - use_pred_info_t i1, i2; - vec<use_pred_info_t> const *chain1 - = (vec<use_pred_info_t> const *)p1; - vec<use_pred_info_t> const *chain2 - = (vec<use_pred_info_t> const *)p2; - - if (chain1->length () != chain2->length ()) - return (chain1->length () - chain2->length ()); - - i1 = (*chain1)[0]; - i2 = (*chain2)[0]; - - /* Allow predicates with similar prefix come together. */ - if (!i1->invert && i2->invert) - return -1; - else if (i1->invert && !i2->invert) - return 1; - - return gimple_uid (i1->cond) - gimple_uid (i2->cond); -} - -/* x OR (!x AND y) is equivalent to x OR y. - This function normalizes x1 OR (!x1 AND x2) OR (!x1 AND !x2 AND x3) - into x1 OR x2 OR x3. PREDS is the predicate chains, and N is - the number of chains. Returns true if normalization happens. */ - -static bool -normalize_preds (vec<use_pred_info_t> *preds, size_t *n) -{ - size_t i, j, ll; - vec<use_pred_info_t> pred_chain; - vec<use_pred_info_t> x = vNULL; - use_pred_info_t xj = 0, nxj = 0; - - if (*n < 2) - return false; - - /* First sort the chains in ascending order of lengths. */ - qsort (preds, *n, sizeof (void *), pred_chain_length_cmp); - pred_chain = preds[0]; - ll = pred_chain.length (); - if (ll != 1) - { - if (ll == 2) - { - use_pred_info_t xx, yy, xx2, nyy; - vec<use_pred_info_t> pred_chain2 = preds[1]; - if (pred_chain2.length () != 2) - return false; - - /* See if simplification x AND y OR x AND !y is possible. */ - xx = pred_chain[0]; - yy = pred_chain[1]; - xx2 = pred_chain2[0]; - nyy = pred_chain2[1]; - if (gimple_cond_lhs (xx->cond) != gimple_cond_lhs (xx2->cond) - || gimple_cond_rhs (xx->cond) != gimple_cond_rhs (xx2->cond) - || gimple_cond_code (xx->cond) != gimple_cond_code (xx2->cond) - || (xx->invert != xx2->invert)) - return false; - if (gimple_cond_lhs (yy->cond) != gimple_cond_lhs (nyy->cond) - || gimple_cond_rhs (yy->cond) != gimple_cond_rhs (nyy->cond) - || gimple_cond_code (yy->cond) != gimple_cond_code (nyy->cond) - || (yy->invert == nyy->invert)) - return false; - - /* Now merge the first two chains. */ - free (yy); - free (nyy); - free (xx2); - pred_chain.release (); - pred_chain2.release (); - pred_chain.safe_push (xx); - preds[0] = pred_chain; - for (i = 1; i < *n - 1; i++) - preds[i] = preds[i + 1]; - - preds[*n - 1].create (0); - *n = *n - 1; - } - else - return false; - } - - x.safe_push (pred_chain[0]); - - /* The loop extracts x1, x2, x3, etc from chains - x1 OR (!x1 AND x2) OR (!x1 AND !x2 AND x3) OR ... */ - for (i = 1; i < *n; i++) - { - pred_chain = preds[i]; - if (pred_chain.length () != i + 1) - return false; - - for (j = 0; j < i; j++) - { - xj = x[j]; - nxj = pred_chain[j]; - - /* Check if nxj is !xj */ - if (gimple_cond_lhs (xj->cond) != gimple_cond_lhs (nxj->cond) - || gimple_cond_rhs (xj->cond) != gimple_cond_rhs (nxj->cond) - || gimple_cond_code (xj->cond) != gimple_cond_code (nxj->cond) - || (xj->invert == nxj->invert)) - return false; - } - - x.safe_push (pred_chain[i]); - } - - /* Now normalize the pred chains using the extraced x1, x2, x3 etc. */ - for (j = 0; j < *n; j++) - { - use_pred_info_t t; - xj = x[j]; - - t = XNEW (struct use_pred_info); - *t = *xj; - - x[j] = t; - } - - for (i = 0; i < *n; i++) - { - pred_chain = preds[i]; - for (j = 0; j < pred_chain.length (); j++) - free (pred_chain[j]); - pred_chain.release (); - /* A new chain. */ - pred_chain.safe_push (x[i]); - preds[i] = pred_chain; - } - return true; -} - - - -/* Computes the predicates that guard the use and checks - if the incoming paths that have empty (or possibly - empty) definition can be pruned/filtered. The function returns - true if it can be determined that the use of PHI's def in - USE_STMT is guarded with a predicate set not overlapping with - predicate sets of all runtime paths that do not have a definition. - Returns false if it is not or it can not be determined. USE_BB is - the bb of the use (for phi operand use, the bb is not the bb of - the phi stmt, but the src bb of the operand edge). UNINIT_OPNDS - is a bit vector. If an operand of PHI is uninitialized, the - corresponding bit in the vector is 1. VISIED_PHIS is a pointer - set of phis being visted. */ - -static bool -is_use_properly_guarded (gimple use_stmt, - basic_block use_bb, - gimple phi, - unsigned uninit_opnds, - struct pointer_set_t *visited_phis) -{ - basic_block phi_bb; - vec<use_pred_info_t> *preds = 0; - vec<use_pred_info_t> *def_preds = 0; - size_t num_preds = 0, num_def_preds = 0; - bool has_valid_preds = false; - bool is_properly_guarded = false; - - if (pointer_set_insert (visited_phis, phi)) - return false; - - phi_bb = gimple_bb (phi); - - if (is_non_loop_exit_postdominating (use_bb, phi_bb)) - return false; - - has_valid_preds = find_predicates (&preds, &num_preds, - phi_bb, use_bb); - - if (!has_valid_preds) - { - destroy_predicate_vecs (num_preds, preds); - return false; - } - - if (dump_file) - dump_predicates (use_stmt, num_preds, preds, - "\nUse in stmt "); - - has_valid_preds = find_def_preds (&def_preds, - &num_def_preds, phi); - - if (has_valid_preds) - { - bool normed; - if (dump_file) - dump_predicates (phi, num_def_preds, def_preds, - "Operand defs of phi "); - - normed = normalize_preds (def_preds, &num_def_preds); - if (normed && dump_file) - { - fprintf (dump_file, "\nNormalized to\n"); - dump_predicates (phi, num_def_preds, def_preds, - "Operand defs of phi "); - } - is_properly_guarded = - is_superset_of (def_preds, num_def_preds, - preds, num_preds); - } - - /* further prune the dead incoming phi edges. */ - if (!is_properly_guarded) - is_properly_guarded - = use_pred_not_overlap_with_undef_path_pred ( - num_preds, preds, phi, uninit_opnds, visited_phis); - - destroy_predicate_vecs (num_preds, preds); - destroy_predicate_vecs (num_def_preds, def_preds); - return is_properly_guarded; -} - -/* Searches through all uses of a potentially - uninitialized variable defined by PHI and returns a use - statement if the use is not properly guarded. It returns - NULL if all uses are guarded. UNINIT_OPNDS is a bitvector - holding the position(s) of uninit PHI operands. WORKLIST - is the vector of candidate phis that may be updated by this - function. ADDED_TO_WORKLIST is the pointer set tracking - if the new phi is already in the worklist. */ - -static gimple -find_uninit_use (gimple phi, unsigned uninit_opnds, - vec<gimple> *worklist, - struct pointer_set_t *added_to_worklist) -{ - tree phi_result; - use_operand_p use_p; - gimple use_stmt; - imm_use_iterator iter; - - phi_result = gimple_phi_result (phi); - - FOR_EACH_IMM_USE_FAST (use_p, iter, phi_result) - { - struct pointer_set_t *visited_phis; - basic_block use_bb; - - use_stmt = USE_STMT (use_p); - if (is_gimple_debug (use_stmt)) - continue; - - visited_phis = pointer_set_create (); - - if (gimple_code (use_stmt) == GIMPLE_PHI) - 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, - phi, - uninit_opnds, - visited_phis)) - { - pointer_set_destroy (visited_phis); - continue; - } - 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; - - /* 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); - } - - worklist->safe_push (use_stmt); - pointer_set_insert (possibly_undefined_names, phi_result); - } - } - - return NULL; -} - -/* Look for inputs to PHI that are SSA_NAMEs that have empty definitions - and gives warning if there exists a runtime path from the entry to a - use of the PHI def that does not contain a definition. In other words, - the warning is on the real use. The more dead paths that can be pruned - by the compiler, the fewer false positives the warning is. WORKLIST - is a vector of candidate phis to be examined. ADDED_TO_WORKLIST is - a pointer set tracking if the new phi is added to the worklist or not. */ - -static void -warn_uninitialized_phi (gimple phi, vec<gimple> *worklist, - struct pointer_set_t *added_to_worklist) -{ - unsigned uninit_opnds; - gimple uninit_use_stmt = 0; - tree uninit_op; - - /* Don't look at virtual operands. */ - if (virtual_operand_p (gimple_phi_result (phi))) - return; - - uninit_opnds = compute_uninit_opnds_pos (phi); - - 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); - - /* All uses are properly guarded. */ - if (!uninit_use_stmt) - return; - - uninit_op = gimple_phi_arg_def (phi, MASK_FIRST_SET_BIT (uninit_opnds)); - if (SSA_NAME_VAR (uninit_op) == NULL_TREE) - return; - warn_uninit (OPT_Wmaybe_uninitialized, uninit_op, SSA_NAME_VAR (uninit_op), - SSA_NAME_VAR (uninit_op), - "%qD may be used uninitialized in this function", - uninit_use_stmt); - -} - - -/* Entry point to the late uninitialized warning pass. */ - -static unsigned int -execute_late_warn_uninitialized (void) -{ - basic_block bb; - gimple_stmt_iterator gsi; - vec<gimple> worklist = vNULL; - struct pointer_set_t *added_to_worklist; - - calculate_dominance_info (CDI_DOMINATORS); - calculate_dominance_info (CDI_POST_DOMINATORS); - /* Re-do the plain uninitialized variable check, as optimization may have - straightened control flow. Do this first so that we don't accidentally - get a "may be" warning when we'd have seen an "is" warning later. */ - warn_uninitialized_vars (/*warn_possibly_uninitialized=*/1); - - timevar_push (TV_TREE_UNINIT); - - possibly_undefined_names = pointer_set_create (); - added_to_worklist = pointer_set_create (); - - /* Initialize worklist */ - FOR_EACH_BB (bb) - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple phi = gsi_stmt (gsi); - size_t n, i; - - n = gimple_phi_num_args (phi); - - /* Don't look at virtual operands. */ - if (virtual_operand_p (gimple_phi_result (phi))) - continue; - - for (i = 0; i < n; ++i) - { - tree op = gimple_phi_arg_def (phi, i); - if (TREE_CODE (op) == SSA_NAME - && uninit_undefined_value_p (op)) - { - worklist.safe_push (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; - } - } - } - - while (worklist.length () != 0) - { - gimple cur_phi = 0; - cur_phi = worklist.pop (); - warn_uninitialized_phi (cur_phi, &worklist, added_to_worklist); - } - - worklist.release (); - pointer_set_destroy (added_to_worklist); - pointer_set_destroy (possibly_undefined_names); - possibly_undefined_names = NULL; - free_dominance_info (CDI_POST_DOMINATORS); - timevar_pop (TV_TREE_UNINIT); - return 0; -} - -static bool -gate_warn_uninitialized (void) -{ - return warn_uninitialized != 0; -} - -struct gimple_opt_pass pass_late_warn_uninitialized = -{ - { - GIMPLE_PASS, - "uninit", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - gate_warn_uninitialized, /* gate */ - execute_late_warn_uninitialized, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_NONE, /* tv_id */ - PROP_ssa, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - } -}; |