X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-cfg.c;h=761dce159d1d5be575c509e03288f60473c3a34d;hb=5dee2817fd4f8b8c16c7a8ee0acf43eb3af48fc7;hp=3a0868981470566b1060a5309ce12a9de80992ec;hpb=48e1416a24d50cacbb2a5e06a9ee61dd8cbee313;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 3a086898147..761dce159d1 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -1,6 +1,6 @@ /* Control flow functions for trees. - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 Free Software Foundation, Inc. Contributed by Diego Novillo This file is part of GCC. @@ -71,6 +71,12 @@ static const int initial_cfg_capacity = 20; static struct pointer_map_t *edge_to_cases; +/* If we record edge_to_cases, this bitmap will hold indexes + of basic blocks that end in a GIMPLE_SWITCH which we touched + due to edge manipulations. */ + +static bitmap touched_switch_bbs; + /* CFG statistics. */ struct cfg_stats_d { @@ -122,6 +128,7 @@ static edge find_taken_edge_computed_goto (basic_block, tree); static edge find_taken_edge_cond_expr (basic_block, tree); static edge find_taken_edge_switch_expr (basic_block, tree); static tree find_case_label_for_value (gimple, tree); +static void group_case_labels_stmt (gimple); void init_empty_tree_cfg_for_function (struct function *fn) @@ -848,6 +855,7 @@ start_recording_case_labels (void) { gcc_assert (edge_to_cases == NULL); edge_to_cases = pointer_map_create (); + touched_switch_bbs = BITMAP_ALLOC (NULL); } /* Return nonzero if we are recording information for case labels. */ @@ -863,9 +871,22 @@ recording_case_labels_p (void) void end_recording_case_labels (void) { + bitmap_iterator bi; + unsigned i; pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL); pointer_map_destroy (edge_to_cases); edge_to_cases = NULL; + EXECUTE_IF_SET_IN_BITMAP (touched_switch_bbs, 0, i, bi) + { + basic_block bb = BASIC_BLOCK (i); + if (bb) + { + gimple stmt = last_stmt (bb); + if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + group_case_labels_stmt (stmt); + } + } + BITMAP_FREE (touched_switch_bbs); } /* If we are inside a {start,end}_recording_cases block, then return @@ -1278,108 +1299,115 @@ cleanup_dead_labels (void) free (label_for_bb); } -/* Look for blocks ending in a multiway branch (a SWITCH_EXPR in GIMPLE), - and scan the sorted vector of cases. Combine the ones jumping to the - same label. +/* Scan the sorted vector of cases in STMT (a GIMPLE_SWITCH) and combine + the ones jumping to the same label. Eg. three separate entries 1: 2: 3: become one entry 1..3: */ -void -group_case_labels (void) +static void +group_case_labels_stmt (gimple stmt) { - basic_block bb; + int old_size = gimple_switch_num_labels (stmt); + int i, j, new_size = old_size; + tree default_case = NULL_TREE; + tree default_label = NULL_TREE; + bool has_default; - FOR_EACH_BB (bb) + /* The default label is always the first case in a switch + statement after gimplification if it was not optimized + away */ + if (!CASE_LOW (gimple_switch_default_label (stmt)) + && !CASE_HIGH (gimple_switch_default_label (stmt))) { - gimple stmt = last_stmt (bb); - if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + default_case = gimple_switch_default_label (stmt); + default_label = CASE_LABEL (default_case); + has_default = true; + } + else + has_default = false; + + /* Look for possible opportunities to merge cases. */ + if (has_default) + i = 1; + else + i = 0; + while (i < old_size) + { + tree base_case, base_label, base_high; + base_case = gimple_switch_label (stmt, i); + + gcc_assert (base_case); + base_label = CASE_LABEL (base_case); + + /* Discard cases that have the same destination as the + default case. */ + if (base_label == default_label) { - int old_size = gimple_switch_num_labels (stmt); - int i, j, new_size = old_size; - tree default_case = NULL_TREE; - tree default_label = NULL_TREE; - bool has_default; - - /* The default label is always the first case in a switch - statement after gimplification if it was not optimized - away */ - if (!CASE_LOW (gimple_switch_default_label (stmt)) - && !CASE_HIGH (gimple_switch_default_label (stmt))) + gimple_switch_set_label (stmt, i, NULL_TREE); + i++; + new_size--; + continue; + } + + base_high = CASE_HIGH (base_case) + ? CASE_HIGH (base_case) + : CASE_LOW (base_case); + i++; + + /* Try to merge case labels. Break out when we reach the end + of the label vector or when we cannot merge the next case + label with the current one. */ + while (i < old_size) + { + tree merge_case = gimple_switch_label (stmt, i); + tree merge_label = CASE_LABEL (merge_case); + tree t = int_const_binop (PLUS_EXPR, base_high, + integer_one_node, 1); + + /* Merge the cases if they jump to the same place, + and their ranges are consecutive. */ + if (merge_label == base_label + && tree_int_cst_equal (CASE_LOW (merge_case), t)) { - default_case = gimple_switch_default_label (stmt); - default_label = CASE_LABEL (default_case); - has_default = true; + base_high = CASE_HIGH (merge_case) ? + CASE_HIGH (merge_case) : CASE_LOW (merge_case); + CASE_HIGH (base_case) = base_high; + gimple_switch_set_label (stmt, i, NULL_TREE); + new_size--; + i++; } else - has_default = false; - - /* Look for possible opportunities to merge cases. */ - if (has_default) - i = 1; - else - i = 0; - while (i < old_size) - { - tree base_case, base_label, base_high; - base_case = gimple_switch_label (stmt, i); - - gcc_assert (base_case); - base_label = CASE_LABEL (base_case); + break; + } + } - /* Discard cases that have the same destination as the - default case. */ - if (base_label == default_label) - { - gimple_switch_set_label (stmt, i, NULL_TREE); - i++; - new_size--; - continue; - } + /* Compress the case labels in the label vector, and adjust the + length of the vector. */ + for (i = 0, j = 0; i < new_size; i++) + { + while (! gimple_switch_label (stmt, j)) + j++; + gimple_switch_set_label (stmt, i, + gimple_switch_label (stmt, j++)); + } - base_high = CASE_HIGH (base_case) - ? CASE_HIGH (base_case) - : CASE_LOW (base_case); - i++; + gcc_assert (new_size <= old_size); + gimple_switch_set_num_labels (stmt, new_size); +} - /* Try to merge case labels. Break out when we reach the end - of the label vector or when we cannot merge the next case - label with the current one. */ - while (i < old_size) - { - tree merge_case = gimple_switch_label (stmt, i); - tree merge_label = CASE_LABEL (merge_case); - tree t = int_const_binop (PLUS_EXPR, base_high, - integer_one_node, 1); - - /* Merge the cases if they jump to the same place, - and their ranges are consecutive. */ - if (merge_label == base_label - && tree_int_cst_equal (CASE_LOW (merge_case), t)) - { - base_high = CASE_HIGH (merge_case) ? - CASE_HIGH (merge_case) : CASE_LOW (merge_case); - CASE_HIGH (base_case) = base_high; - gimple_switch_set_label (stmt, i, NULL_TREE); - new_size--; - i++; - } - else - break; - } - } +/* Look for blocks ending in a multiway branch (a GIMPLE_SWITCH), + and scan the sorted vector of cases. Combine the ones jumping to the + same label. */ - /* Compress the case labels in the label vector, and adjust the - length of the vector. */ - for (i = 0, j = 0; i < new_size; i++) - { - while (! gimple_switch_label (stmt, j)) - j++; - gimple_switch_set_label (stmt, i, - gimple_switch_label (stmt, j++)); - } +void +group_case_labels (void) +{ + basic_block bb; - gcc_assert (new_size <= old_size); - gimple_switch_set_num_labels (stmt, new_size); - } + FOR_EACH_BB (bb) + { + gimple stmt = last_stmt (bb); + if (stmt && gimple_code (stmt) == GIMPLE_SWITCH) + group_case_labels_stmt (stmt); } } @@ -1438,27 +1466,12 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b) return false; /* It must be possible to eliminate all phi nodes in B. If ssa form - is not up-to-date, we cannot eliminate any phis; however, if only - some symbols as whole are marked for renaming, this is not a problem, - as phi nodes for those symbols are irrelevant in updating anyway. */ + is not up-to-date and a name-mapping is registered, we cannot eliminate + any phis. Symbols marked for renaming are never a problem though. */ phis = phi_nodes (b); - if (!gimple_seq_empty_p (phis)) - { - gimple_stmt_iterator i; - - if (name_mappings_registered_p ()) - return false; - - for (i = gsi_start (phis); !gsi_end_p (i); gsi_next (&i)) - { - gimple phi = gsi_stmt (i); - - if (!is_gimple_reg (gimple_phi_result (phi)) - && !may_propagate_copy (gimple_phi_result (phi), - gimple_phi_arg_def (phi, 0))) - return false; - } - } + if (!gimple_seq_empty_p (phis) + && name_mappings_registered_p ()) + return false; return true; } @@ -1632,6 +1645,9 @@ gimple_merge_blocks (basic_block a, basic_block b) FOR_EACH_IMM_USE_STMT (stmt, iter, def) FOR_EACH_IMM_USE_ON_STMT (use_p, iter) SET_USE (use_p, use); + + if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def)) + SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use) = 1; } else replace_uses_by (def, use); @@ -1760,7 +1776,6 @@ static void remove_bb (basic_block bb) { gimple_stmt_iterator i; - source_location loc = UNKNOWN_LOCATION; if (dump_file) { @@ -1830,24 +1845,9 @@ remove_bb (basic_block bb) i = gsi_last_bb (bb); else gsi_prev (&i); - - /* Don't warn for removed gotos. Gotos are often removed due to - jump threading, thus resulting in bogus warnings. Not great, - since this way we lose warnings for gotos in the original - program that are indeed unreachable. */ - if (gimple_code (stmt) != GIMPLE_GOTO - && gimple_has_location (stmt)) - loc = gimple_location (stmt); } } - /* If requested, give a warning that the first statement in the - block is unreachable. We walk statements backwards in the - loop above, so the last statement we process is the first statement - in the block. */ - if (loc > BUILTINS_LOCATION && LOCATION_LINE (loc) > 0) - warning_at (loc, OPT_Wunreachable_code, "will never be executed"); - remove_phi_nodes_and_edges_for_unreachable_block (bb); bb->il.gimple = NULL; } @@ -2246,7 +2246,7 @@ is_ctrl_altering_stmt (gimple t) return true; /* A call also alters control flow if it does not return. */ - if (gimple_call_flags (t) & ECF_NORETURN) + if (flags & ECF_NORETURN) return true; } break; @@ -2953,6 +2953,15 @@ verify_gimple_call (gimple stmt) { tree fn = gimple_call_fn (stmt); tree fntype; + unsigned i; + + if (TREE_CODE (fn) != OBJ_TYPE_REF + && !is_gimple_val (fn)) + { + error ("invalid function in gimple call"); + debug_generic_stmt (fn); + return true; + } if (!POINTER_TYPE_P (TREE_TYPE (fn)) || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE @@ -2970,6 +2979,12 @@ verify_gimple_call (gimple stmt) return true; } + if (gimple_call_lhs (stmt) && gimple_call_noreturn_p (stmt)) + { + error ("LHS in noreturn call"); + return true; + } + fntype = TREE_TYPE (TREE_TYPE (fn)); if (gimple_call_lhs (stmt) && !useless_type_conversion_p (TREE_TYPE (gimple_call_lhs (stmt)), @@ -2988,6 +3003,14 @@ verify_gimple_call (gimple stmt) return true; } + if (gimple_call_chain (stmt) + && !is_gimple_val (gimple_call_chain (stmt))) + { + error ("invalid static chain in gimple call"); + debug_generic_stmt (gimple_call_chain (stmt)); + return true; + } + /* If there is a static chain argument, this should not be an indirect call, and the decl should have DECL_STATIC_CHAIN set. */ if (gimple_call_chain (stmt)) @@ -3009,9 +3032,19 @@ verify_gimple_call (gimple stmt) /* ??? The C frontend passes unpromoted arguments in case it didn't see a function declaration before the call. So for now - leave the call arguments unverified. Once we gimplify + leave the call arguments mostly unverified. Once we gimplify unit-at-a-time we have a chance to fix this. */ + for (i = 0; i < gimple_call_num_args (stmt); ++i) + { + tree arg = gimple_call_arg (stmt, i); + if (!is_gimple_operand (arg)) + { + error ("invalid argument to gimple call"); + debug_generic_expr (arg); + } + } + return false; } @@ -3270,13 +3303,13 @@ verify_gimple_assign_binary (gimple stmt) if ((!INTEGRAL_TYPE_P (rhs1_type) && !FIXED_POINT_TYPE_P (rhs1_type) && !(TREE_CODE (rhs1_type) == VECTOR_TYPE - && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE)) + && INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type)))) || (!INTEGRAL_TYPE_P (rhs2_type) /* Vector shifts of vectors are also ok. */ && !(TREE_CODE (rhs1_type) == VECTOR_TYPE - && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE + && INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type)) && TREE_CODE (rhs2_type) == VECTOR_TYPE - && TREE_CODE (TREE_TYPE (rhs2_type)) == INTEGER_TYPE)) + && INTEGRAL_TYPE_P (TREE_TYPE (rhs2_type)))) || !useless_type_conversion_p (lhs_type, rhs1_type)) { error ("type mismatch in shift expression"); @@ -3422,8 +3455,13 @@ do_pointer_plus_expr_check: connected to the operand types. */ return verify_gimple_comparison (lhs_type, rhs1, rhs2); - case WIDEN_SUM_EXPR: case WIDEN_MULT_EXPR: + if (TREE_CODE (lhs_type) != INTEGER_TYPE) + return true; + return ((2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type)) + || (TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type))); + + case WIDEN_SUM_EXPR: case VEC_WIDEN_MULT_HI_EXPR: case VEC_WIDEN_MULT_LO_EXPR: case VEC_PACK_TRUNC_EXPR: @@ -3760,6 +3798,20 @@ verify_types_in_gimple_stmt (gimple stmt) return verify_gimple_call (stmt); case GIMPLE_COND: + if (TREE_CODE_CLASS (gimple_cond_code (stmt)) != tcc_comparison) + { + error ("invalid comparison code in gimple cond"); + return true; + } + if (!(!gimple_cond_true_label (stmt) + || TREE_CODE (gimple_cond_true_label (stmt)) == LABEL_DECL) + || !(!gimple_cond_false_label (stmt) + || TREE_CODE (gimple_cond_false_label (stmt)) == LABEL_DECL)) + { + error ("invalid labels in gimple cond"); + return true; + } + return verify_gimple_comparison (boolean_type_node, gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); @@ -4237,6 +4289,15 @@ gimple_verify_flow_info (void) err = 1; } + if (prev_stmt && EH_LANDING_PAD_NR (label) != 0) + { + error ("EH landing pad label "); + print_generic_expr (stderr, label, 0); + fprintf (stderr, " is not first in a sequence of labels in bb %d", + bb->index); + err = 1; + } + if (label_to_block (label) != bb) { error ("label "); @@ -4661,6 +4722,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) TREE_CHAIN (last) = TREE_CHAIN (cases2); TREE_CHAIN (cases2) = first; } + bitmap_set_bit (touched_switch_bbs, gimple_bb (stmt)->index); } else { @@ -4887,31 +4949,6 @@ gimple_duplicate_bb (basic_block bb) return new_bb; } -/* Add phi arguments to the phi nodes in E_COPY->dest according to - the phi arguments coming from the equivalent edge at - the phi nodes of DEST. */ - -static void -add_phi_args_after_redirect (edge e_copy, edge orig_e) -{ - gimple_stmt_iterator psi, psi_copy; - gimple phi, phi_copy; - tree def; - - for (psi = gsi_start_phis (orig_e->dest), - psi_copy = gsi_start_phis (e_copy->dest); - !gsi_end_p (psi); - gsi_next (&psi), gsi_next (&psi_copy)) - { - - phi = gsi_stmt (psi); - phi_copy = gsi_stmt (psi_copy); - def = PHI_ARG_DEF_FROM_EDGE (phi, orig_e); - add_phi_arg (phi_copy, def, e_copy, - gimple_phi_arg_location_from_edge (phi, orig_e)); - } -} - /* Adds phi node arguments for edge E_COPY after basic block duplication. */ static void @@ -5195,12 +5232,13 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU edge exits[2], nexits[2], e; gimple_stmt_iterator gsi,gsi1; gimple cond_stmt; - edge sorig, snew, orig_e; + edge sorig, snew; basic_block exit_bb; - edge_iterator ei; - VEC (edge, heap) *redirect_edges; - basic_block iters_bb, orig_src; + basic_block iters_bb; tree new_rhs; + gimple_stmt_iterator psi; + gimple phi; + tree def; gcc_assert (EDGE_COUNT (exit->src->succs) == 2); exits[0] = exit; @@ -5209,17 +5247,6 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU if (!can_copy_bbs_p (region, n_region)) return false; - /* Some sanity checking. Note that we do not check for all possible - missuses of the functions. I.e. if you ask to copy something weird - (e.g., in the example, if there is a jump from inside to the middle - of some_code, or come_code defines some of the values used in cond) - it will work, but the resulting code will not be correct. */ - for (i = 0; i < n_region; i++) - { - if (region[i] == orig_loop->latch) - return false; - } - initialize_original_copy_tables (); set_loop_copy (orig_loop, loop); duplicate_subloops (orig_loop, loop); @@ -5337,72 +5364,30 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU e = redirect_edge_and_branch (exits[0], exits[1]->dest); PENDING_STMT (e) = NULL; - /* If the block consisting of the exit condition has the latch as - successor, then the body of the loop is executed before - the exit condition is tested. - - { body } - { cond } (exit[0]) -> { latch } - | - V (exit[1]) - - { exit_bb } - - - In such case, the equivalent copied edge nexits[1] - (for the peeled iteration) needs to be redirected to exit_bb. - - Otherwise, - - { cond } (exit[0]) -> { body } - | - V (exit[1]) - - { exit_bb } - - - exit[0] is pointing to the body of the loop, - and the equivalent nexits[0] needs to be redirected to - the copied body (of the peeled iteration). */ - - if (exits[1]->dest == orig_loop->latch) - e = redirect_edge_and_branch (nexits[1], nexits[0]->dest); - else - e = redirect_edge_and_branch (nexits[0], nexits[1]->dest); - PENDING_STMT (e) = NULL; - - redirect_edges = VEC_alloc (edge, heap, 10); - - for (i = 0; i < n_region; i++) - region_copy[i]->flags |= BB_DUPLICATED; - - /* Iterate all incoming edges to latch. All those coming from - copied bbs will be redirected to exit_bb. */ - FOR_EACH_EDGE (e, ei, orig_loop->latch->preds) - { - if (e->src->flags & BB_DUPLICATED) - VEC_safe_push (edge, heap, redirect_edges, e); - } - + /* The latch of ORIG_LOOP was copied, and so was the backedge + to the original header. We redirect this backedge to EXIT_BB. */ for (i = 0; i < n_region; i++) - region_copy[i]->flags &= ~BB_DUPLICATED; - - for (i = 0; VEC_iterate (edge, redirect_edges, i, e); ++i) - { - e = redirect_edge_and_branch (e, exit_bb); - PENDING_STMT (e) = NULL; - orig_src = get_bb_original (e->src); - orig_e = find_edge (orig_src, orig_loop->latch); - add_phi_args_after_redirect (e, orig_e); - } - - VEC_free (edge, heap, redirect_edges); - + if (get_bb_original (region_copy[i]) == orig_loop->latch) + { + gcc_assert (single_succ_edge (region_copy[i])); + e = redirect_edge_and_branch (single_succ_edge (region_copy[i]), exit_bb); + PENDING_STMT (e) = NULL; + for (psi = gsi_start_phis (exit_bb); + !gsi_end_p (psi); + gsi_next (&psi)) + { + phi = gsi_stmt (psi); + def = PHI_ARG_DEF (phi, nexits[0]->dest_idx); + add_phi_arg (phi, def, e, gimple_phi_arg_location_from_edge (phi, e)); + } + } + e = redirect_edge_and_branch (nexits[0], nexits[1]->dest); + PENDING_STMT (e) = NULL; + /* Anything that is outside of the region, but was dominated by something inside needs to update dominance info. */ iterate_fix_dominators (CDI_DOMINATORS, doms, false); VEC_free (basic_block, heap, doms); - /* Update the SSA web. */ update_ssa (TODO_update_ssa); @@ -6897,7 +6882,7 @@ gimple_execute_on_growing_pred (edge e) { basic_block bb = e->dest; - if (phi_nodes (bb)) + if (!gimple_seq_empty_p (phi_nodes (bb))) reserve_phi_args_for_new_edge (bb); } @@ -6907,7 +6892,7 @@ gimple_execute_on_growing_pred (edge e) static void gimple_execute_on_shrinking_pred (edge e) { - if (phi_nodes (e->dest)) + if (!gimple_seq_empty_p (phi_nodes (e->dest))) remove_phi_args (e); }