On Fri, 16 Jan 2015, Jakub Jelinek wrote: > On Fri, Jan 16, 2015 at 02:02:37PM +0100, Richard Biener wrote: > > > > The following fixes PR64614, maybe-uninit warnings in switches > > and guards like X & 3. > > > > The support for switches is quite limited (because the predicate > > infrastructure in the pass is quite limited), but it seems to > > handle this particular case at least. > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu. > > > > Any idea how to better handle the case label lookup? Unfortunately > > the pass doesn't have a general information gathering phase or a > > lattice... Maybe we just don't care? Or put in an arbitrary > > limit on gimple_switch_num_labels we handle? > > The pass already has various other limits: > #define MAX_NUM_CHAINS 8 > #define MAX_CHAIN_LEN 5 > #define MAX_POSTDOM_CHECK 8 > I'd just add MAX_SWITCH_CASES 40
Done, committed as follows. Richard. 2015-01-16 Richard Biener <rguent...@suse.de> PR middle-end/64614 * tree-ssa-uninit.c: Include tree-cfg.h. (MAX_SWITCH_CASES): New define. (convert_control_dep_chain_into_preds): Handle switch statements. (is_pred_expr_subset_of): Handle x == CST vs. (x & CST) != 0. (normalize_one_pred_1): Do not split bit-manipulations. Record (x & CST). * gcc.dg/uninit-18.c: New testcase. Index: gcc/tree-ssa-uninit.c =================================================================== *** gcc/tree-ssa-uninit.c.orig 2015-01-16 14:14:18.135193759 +0100 --- gcc/tree-ssa-uninit.c 2015-01-16 14:16:16.635189656 +0100 *************** along with GCC; see the file COPYING3. *** 58,63 **** --- 58,64 ---- #include "tree-pass.h" #include "diagnostic-core.h" #include "params.h" + #include "tree-cfg.h" /* This implements the pass that does predicate aware warning on uses of possibly uninitialized variables. The pass first collects the set of *************** find_control_equiv_block (basic_block bb *** 411,416 **** --- 412,418 ---- #define MAX_NUM_CHAINS 8 #define MAX_CHAIN_LEN 5 #define MAX_POSTDOM_CHECK 8 + #define MAX_SWITCH_CASES 40 /* Computes the control dependence chains (paths of edges) for DEP_BB up to the dominating basic block BB (the head node of a *************** convert_control_dep_chain_into_preds (ve *** 592,608 **** if (skip) continue; } ! if (gimple_code (cond_stmt) != GIMPLE_COND) { has_valid_pred = false; break; } - one_pred.pred_lhs = gimple_cond_lhs (cond_stmt); - one_pred.pred_rhs = gimple_cond_rhs (cond_stmt); - one_pred.cond_code = gimple_cond_code (cond_stmt); - one_pred.invert = !!(e->flags & EDGE_FALSE_VALUE); - t_chain.safe_push (one_pred); - has_valid_pred = true; } if (!has_valid_pred) --- 594,656 ---- if (skip) continue; } ! if (gimple_code (cond_stmt) == GIMPLE_COND) ! { ! one_pred.pred_lhs = gimple_cond_lhs (cond_stmt); ! one_pred.pred_rhs = gimple_cond_rhs (cond_stmt); ! one_pred.cond_code = gimple_cond_code (cond_stmt); ! one_pred.invert = !!(e->flags & EDGE_FALSE_VALUE); ! t_chain.safe_push (one_pred); ! has_valid_pred = true; ! } ! else if (gswitch *gs = dyn_cast <gswitch *> (cond_stmt)) ! { ! /* Avoid quadratic behavior. */ ! if (gimple_switch_num_labels (gs) > MAX_SWITCH_CASES) ! { ! has_valid_pred = false; ! break; ! } ! /* Find the case label. */ ! tree l = NULL_TREE; ! unsigned idx; ! for (idx = 0; idx < gimple_switch_num_labels (gs); ++idx) ! { ! tree tl = gimple_switch_label (gs, idx); ! if (e->dest == label_to_block (CASE_LABEL (tl))) ! { ! if (!l) ! l = tl; ! else ! { ! l = NULL_TREE; ! break; ! } ! } ! } ! /* If more than one label reaches this block or the case ! label doesn't have a single value (like the default one) ! fail. */ ! if (!l ! || !CASE_LOW (l) ! || (CASE_HIGH (l) && !operand_equal_p (CASE_LOW (l), ! CASE_HIGH (l), 0))) ! { ! has_valid_pred = false; ! break; ! } ! one_pred.pred_lhs = gimple_switch_index (gs); ! one_pred.pred_rhs = CASE_LOW (l); ! one_pred.cond_code = EQ_EXPR; ! one_pred.invert = false; ! t_chain.safe_push (one_pred); ! has_valid_pred = true; ! } ! else { has_valid_pred = false; break; } } if (!has_valid_pred) *************** is_pred_expr_subset_of (pred_info expr1, *** 1329,1334 **** --- 1377,1386 ---- if (expr2.invert) code2 = invert_tree_comparison (code2, false); + if (code1 == EQ_EXPR && code2 == BIT_AND_EXPR) + return wi::eq_p (expr1.pred_rhs, + wi::bit_and (expr1.pred_rhs, expr2.pred_rhs)); + if (code1 != code2 && code2 != NE_EXPR) return false; *************** normalize_one_pred_1 (pred_chain_union * *** 1970,1977 **** } else if (gimple_assign_rhs_code (def_stmt) == and_or_code) { ! push_to_worklist (gimple_assign_rhs1 (def_stmt), work_list, mark_set); ! push_to_worklist (gimple_assign_rhs2 (def_stmt), work_list, mark_set); } else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) == tcc_comparison) --- 2022,2046 ---- } else if (gimple_assign_rhs_code (def_stmt) == and_or_code) { ! /* Avoid splitting up bit manipulations like x & 3 or y | 1. */ ! if (is_gimple_min_invariant (gimple_assign_rhs2 (def_stmt))) ! { ! /* But treat x & 3 as condition. */ ! if (and_or_code == BIT_AND_EXPR) ! { ! pred_info n_pred; ! n_pred.pred_lhs = gimple_assign_rhs1 (def_stmt); ! n_pred.pred_rhs = gimple_assign_rhs2 (def_stmt); ! n_pred.cond_code = and_or_code; ! n_pred.invert = false; ! norm_chain->safe_push (n_pred); ! } ! } ! else ! { ! push_to_worklist (gimple_assign_rhs1 (def_stmt), work_list, mark_set); ! push_to_worklist (gimple_assign_rhs2 (def_stmt), work_list, mark_set); ! } } else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) == tcc_comparison) Index: gcc/testsuite/gcc.dg/uninit-18.c =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- gcc/testsuite/gcc.dg/uninit-18.c 2015-01-16 14:14:28.304193407 +0100 *************** *** 0 **** --- 1,24 ---- + /* { dg-do compile } */ + /* { dg-options "-O -Wuninitialized" } */ + + char *foo(int bar, char *baz) + { + char *tmp; + + if (bar & 3) + tmp = baz; + + switch (bar) { + case 1: + tmp[5] = 7; /* { dg-bogus "may be used uninitialized" } */ + break; + case 2: + tmp[11] = 15; /* { dg-bogus "may be used uninitialized" } */ + break; + default: + tmp = 0; + break; + } + + return tmp; /* { dg-bogus "may be used uninitialized" } */ + }