X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-cfg.c;h=1f533a33086fbcf4b2b0928c1839876d43799aa8;hb=381d8e2109c307de7a8e2091e24ba83b1db82f05;hp=ec69dd8907078db8183e640be45cf8c3cbc80f1e;hpb=ce084dfc1cd60d867d38dbed86a914d82fa908d1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index ec69dd89070..1f533a33086 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -29,17 +29,15 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "flags.h" #include "function.h" -#include "expr.h" #include "ggc.h" #include "langhooks.h" -#include "diagnostic.h" #include "tree-pretty-print.h" #include "gimple-pretty-print.h" #include "tree-flow.h" #include "timevar.h" #include "tree-dump.h" #include "tree-pass.h" -#include "toplev.h" +#include "diagnostic-core.h" #include "except.h" #include "cfgloop.h" #include "cfglayout.h" @@ -231,10 +229,6 @@ build_gimple_cfg (gimple_seq seq) dump_end (TDI_vcg, vcg_file); } } - -#ifdef ENABLE_CHECKING - verify_stmts (); -#endif } static unsigned int @@ -438,13 +432,13 @@ create_bb (void *h, void *e, basic_block after) gcc_assert (!e); /* Create and initialize a new basic block. Since alloc_block uses - ggc_alloc_cleared to allocate a basic block, we do not have to - clear the newly allocated basic block here. */ + GC allocation that clears memory to allocate a basic block, we do + not have to clear the newly allocated basic block here. */ bb = alloc_block (); bb->index = last_basic_block; bb->flags = BB_NEW; - bb->il.gimple = GGC_CNEW (struct gimple_bb_info); + bb->il.gimple = ggc_alloc_cleared_gimple_bb_info (); set_bb_seq (bb, h ? (gimple_seq) h : gimple_seq_alloc ()); /* Add the new block to the linked list of blocks. */ @@ -568,8 +562,12 @@ make_edges (void) create abnormal edges to them. */ make_eh_edges (last); + /* BUILTIN_RETURN is really a return statement. */ + if (gimple_call_builtin_p (last, BUILT_IN_RETURN)) + make_edge (bb, EXIT_BLOCK_PTR, 0), fallthru = false; /* Some calls are known not to return. */ - fallthru = !(gimple_call_flags (last) & ECF_NORETURN); + else + fallthru = !(gimple_call_flags (last) & ECF_NORETURN); break; case GIMPLE_ASSIGN: @@ -964,7 +962,7 @@ label_to_block_fn (struct function *ifun, tree dest) /* We would die hard when faced by an undefined label. Emit a label to the very first basic block. This will hopefully make even the dataflow and undefined variable warnings quite right. */ - if ((errorcount || sorrycount) && uid < 0) + if (seen_error () && uid < 0) { gimple_stmt_iterator gsi = gsi_start_bb (BASIC_BLOCK (NUM_FIXED_BLOCKS)); gimple stmt; @@ -1473,6 +1471,23 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b) && name_mappings_registered_p ()) return false; + /* When not optimizing, don't merge if we'd lose goto_locus. */ + if (!optimize + && single_succ_edge (a)->goto_locus != UNKNOWN_LOCATION) + { + location_t goto_locus = single_succ_edge (a)->goto_locus; + gimple_stmt_iterator prev, next; + prev = gsi_last_nondebug_bb (a); + next = gsi_after_labels (b); + if (!gsi_end_p (next) && is_gimple_debug (gsi_stmt (next))) + gsi_next_nondebug (&next); + if ((gsi_end_p (prev) + || gimple_location (gsi_stmt (prev)) != goto_locus) + && (gsi_end_p (next) + || gimple_location (gsi_stmt (next)) != goto_locus)) + return false; + } + return true; } @@ -1554,7 +1569,7 @@ replace_uses_by (tree name, tree val) size_t i; fold_stmt_inplace (stmt); - if (cfgcleanup_altered_bbs) + if (cfgcleanup_altered_bbs && !is_gimple_debug (stmt)) bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index); /* FIXME. This should go in update_stmt. */ @@ -2110,7 +2125,7 @@ dump_cfg_stats (FILE *file) /* Dump CFG statistics on stderr. Keep extern so that it's always linked in the final executable. */ -void +DEBUG_FUNCTION void debug_cfg_stats (void) { dump_cfg_stats (stderr); @@ -2242,12 +2257,17 @@ is_ctrl_altering_stmt (gimple t) /* A non-pure/const call alters flow control if the current function has nonlocal labels. */ - if (!(flags & (ECF_CONST | ECF_PURE)) && cfun->has_nonlocal_label) + if (!(flags & (ECF_CONST | ECF_PURE | ECF_LEAF)) + && cfun->has_nonlocal_label) return true; /* A call also alters control flow if it does not return. */ if (flags & ECF_NORETURN) return true; + + /* BUILT_IN_RETURN call is same as return statement. */ + if (gimple_call_builtin_p (t, BUILT_IN_RETURN)) + return true; } break; @@ -2294,7 +2314,8 @@ stmt_can_make_abnormal_goto (gimple t) if (computed_goto_p (t)) return true; if (is_gimple_call (t)) - return gimple_has_side_effects (t) && cfun->has_nonlocal_label; + return (gimple_has_side_effects (t) && cfun->has_nonlocal_label + && !(gimple_call_flags (t) & ECF_LEAF)); return false; } @@ -2510,6 +2531,49 @@ gimple_split_edge (edge edge_in) return new_bb; } + +/* Verify properties of the address expression T with base object BASE. */ + +static tree +verify_address (tree t, tree base) +{ + bool old_constant; + bool old_side_effects; + bool new_constant; + bool new_side_effects; + + old_constant = TREE_CONSTANT (t); + old_side_effects = TREE_SIDE_EFFECTS (t); + + recompute_tree_invariant_for_addr_expr (t); + new_side_effects = TREE_SIDE_EFFECTS (t); + new_constant = TREE_CONSTANT (t); + + if (old_constant != new_constant) + { + error ("constant not recomputed when ADDR_EXPR changed"); + return t; + } + if (old_side_effects != new_side_effects) + { + error ("side effects not recomputed when ADDR_EXPR changed"); + return t; + } + + if (!(TREE_CODE (base) == VAR_DECL + || TREE_CODE (base) == PARM_DECL + || TREE_CODE (base) == RESULT_DECL)) + return NULL_TREE; + + if (DECL_GIMPLE_REG_P (base)) + { + error ("DECL_GIMPLE_REG_P set on a variable with address taken"); + return base; + } + + return NULL_TREE; +} + /* Callback for walk_tree, check that all elements with address taken are properly noticed as such. The DATA is an int* that is 1 if TP was seen inside a PHI node. */ @@ -2538,12 +2602,27 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) break; case INDIRECT_REF: + error ("INDIRECT_REF in gimple IL"); + return t; + + case MEM_REF: x = TREE_OPERAND (t, 0); - if (!is_gimple_reg (x) && !is_gimple_min_invariant (x)) + if (!POINTER_TYPE_P (TREE_TYPE (x)) + || !is_gimple_mem_ref_addr (x)) { - error ("Indirect reference's operand is not a register or a constant."); + error ("invalid first operand of MEM_REF"); return x; } + if (TREE_CODE (TREE_OPERAND (t, 1)) != INTEGER_CST + || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1)))) + { + error ("invalid offset operand of MEM_REF"); + return TREE_OPERAND (t, 1); + } + if (TREE_CODE (x) == ADDR_EXPR + && (x = verify_address (x, TREE_OPERAND (x, 0)))) + return x; + *walk_subtrees = 0; break; case ASSERT_EXPR: @@ -2556,36 +2635,15 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) break; case MODIFY_EXPR: - error ("MODIFY_EXPR not expected while having tuples."); + error ("MODIFY_EXPR not expected while having tuples"); return *tp; case ADDR_EXPR: { - bool old_constant; - bool old_side_effects; - bool new_constant; - bool new_side_effects; + tree tem; gcc_assert (is_gimple_address (t)); - old_constant = TREE_CONSTANT (t); - old_side_effects = TREE_SIDE_EFFECTS (t); - - recompute_tree_invariant_for_addr_expr (t); - new_side_effects = TREE_SIDE_EFFECTS (t); - new_constant = TREE_CONSTANT (t); - - if (old_constant != new_constant) - { - error ("constant not recomputed when ADDR_EXPR changed"); - return t; - } - if (old_side_effects != new_side_effects) - { - error ("side effects not recomputed when ADDR_EXPR changed"); - return t; - } - /* Skip any references (they will be checked when we recurse down the tree) and ensure that any variable used as a prefix is marked addressable. */ @@ -2594,20 +2652,19 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) x = TREE_OPERAND (x, 0)) ; + if ((tem = verify_address (t, x))) + return tem; + if (!(TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL || TREE_CODE (x) == RESULT_DECL)) return NULL; + if (!TREE_ADDRESSABLE (x)) { error ("address taken, but ADDRESSABLE bit not set"); return x; } - if (DECL_GIMPLE_REG_P (x)) - { - error ("DECL_GIMPLE_REG_P set on a variable with address taken"); - return x; - } break; } @@ -2725,7 +2782,7 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) TREE_TYPE (TREE_OPERAND (t, 1)))) { error ("invalid operand to pointer plus, second operand is not an " - "integer with type of sizetype."); + "integer with type of sizetype"); return t; } /* FALLTHROUGH */ @@ -2792,8 +2849,8 @@ verify_types_in_gimple_min_lval (tree expr) if (is_gimple_id (expr)) return false; - if (!INDIRECT_REF_P (expr) - && TREE_CODE (expr) != TARGET_MEM_REF) + if (TREE_CODE (expr) != TARGET_MEM_REF + && TREE_CODE (expr) != MEM_REF) { error ("invalid expression for min lvalue"); return true; @@ -2810,14 +2867,7 @@ verify_types_in_gimple_min_lval (tree expr) debug_generic_stmt (op); return true; } - if (!useless_type_conversion_p (TREE_TYPE (expr), - TREE_TYPE (TREE_TYPE (op)))) - { - error ("type mismatch in indirect reference"); - debug_generic_stmt (TREE_TYPE (expr)); - debug_generic_stmt (TREE_TYPE (TREE_TYPE (op))); - return true; - } + /* Memory references now generally can involve a value conversion. */ return false; } @@ -2900,7 +2950,14 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue) && (TREE_CODE (op) == SSA_NAME || is_gimple_min_invariant (op))) { - error ("Conversion of an SSA_NAME on the left hand side."); + error ("conversion of an SSA_NAME on the left hand side"); + debug_generic_stmt (expr); + return true; + } + else if (TREE_CODE (op) == SSA_NAME + && TYPE_SIZE (TREE_TYPE (expr)) != TYPE_SIZE (TREE_TYPE (op))) + { + error ("conversion of register to a different size"); debug_generic_stmt (expr); return true; } @@ -2911,6 +2968,40 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue) expr = op; } + if (TREE_CODE (expr) == MEM_REF) + { + if (!is_gimple_mem_ref_addr (TREE_OPERAND (expr, 0))) + { + error ("invalid address operand in MEM_REF"); + debug_generic_stmt (expr); + return true; + } + if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST + || !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))) + { + error ("invalid offset operand in MEM_REF"); + debug_generic_stmt (expr); + return true; + } + } + else if (TREE_CODE (expr) == TARGET_MEM_REF) + { + if (!TMR_BASE (expr) + || !is_gimple_mem_ref_addr (TMR_BASE (expr))) + { + error ("invalid address operand in in TARGET_MEM_REF"); + return true; + } + if (!TMR_OFFSET (expr) + || TREE_CODE (TMR_OFFSET (expr)) != INTEGER_CST + || !POINTER_TYPE_P (TREE_TYPE (TMR_OFFSET (expr)))) + { + error ("invalid offset operand in TARGET_MEM_REF"); + debug_generic_stmt (expr); + return true; + } + } + return ((require_lvalue || !is_gimple_min_invariant (expr)) && verify_types_in_gimple_min_lval (expr)); } @@ -3015,8 +3106,7 @@ verify_gimple_call (gimple stmt) call, and the decl should have DECL_STATIC_CHAIN set. */ if (gimple_call_chain (stmt)) { - if (TREE_CODE (fn) != ADDR_EXPR - || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL) + if (!gimple_call_fndecl (stmt)) { error ("static chain in indirect gimple call"); return true; @@ -3025,7 +3115,7 @@ verify_gimple_call (gimple stmt) if (!DECL_STATIC_CHAIN (fn)) { - error ("static chain with function that doesn't use one"); + error ("static chain with function that doesn%'t use one"); return true; } } @@ -3038,10 +3128,14 @@ verify_gimple_call (gimple stmt) for (i = 0; i < gimple_call_num_args (stmt); ++i) { tree arg = gimple_call_arg (stmt, i); - if (!is_gimple_operand (arg)) + if ((is_gimple_reg_type (TREE_TYPE (arg)) + && !is_gimple_val (arg)) + || (!is_gimple_reg_type (TREE_TYPE (arg)) + && !is_gimple_lvalue (arg))) { error ("invalid argument to gimple call"); debug_generic_expr (arg); + return true; } } @@ -3327,6 +3421,7 @@ verify_gimple_assign_binary (gimple stmt) { if (TREE_CODE (rhs1_type) != VECTOR_TYPE || !(INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type)) + || POINTER_TYPE_P (TREE_TYPE (rhs1_type)) || FIXED_POINT_TYPE_P (TREE_TYPE (rhs1_type)) || SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs1_type))) || (!INTEGRAL_TYPE_P (rhs2_type) @@ -3340,9 +3435,9 @@ verify_gimple_assign_binary (gimple stmt) debug_generic_expr (rhs2_type); return true; } - /* For shifting a vector of floating point components we + /* For shifting a vector of non-integral components we only allow shifting by a constant multiple of the element size. */ - if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs1_type)) + if (!INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type)) && (TREE_CODE (rhs2) != INTEGER_CST || !div_if_zero_remainder (EXACT_DIV_EXPR, rhs2, TYPE_SIZE (TREE_TYPE (rhs1_type))))) @@ -3355,8 +3450,9 @@ verify_gimple_assign_binary (gimple stmt) } case PLUS_EXPR: + case MINUS_EXPR: { - /* We use regular PLUS_EXPR for vectors. + /* We use regular PLUS_EXPR and MINUS_EXPR for vectors. ??? This just makes the checker happy and may not be what is intended. */ if (TREE_CODE (lhs_type) == VECTOR_TYPE @@ -3381,10 +3477,6 @@ verify_gimple_assign_binary (gimple stmt) } goto do_pointer_plus_expr_check; } - } - /* Fallthru. */ - case MINUS_EXPR: - { if (POINTER_TYPE_P (lhs_type) || POINTER_TYPE_P (rhs1_type) || POINTER_TYPE_P (rhs2_type)) @@ -3510,6 +3602,79 @@ do_pointer_plus_expr_check: return false; } +/* Verify a gimple assignment statement STMT with a ternary rhs. + Returns true if anything is wrong. */ + +static bool +verify_gimple_assign_ternary (gimple stmt) +{ + enum tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree lhs = gimple_assign_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs1_type = TREE_TYPE (rhs1); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree rhs2_type = TREE_TYPE (rhs2); + tree rhs3 = gimple_assign_rhs3 (stmt); + tree rhs3_type = TREE_TYPE (rhs3); + + if (!is_gimple_reg (lhs) + && !(optimize == 0 + && TREE_CODE (lhs_type) == COMPLEX_TYPE)) + { + error ("non-register as LHS of ternary operation"); + return true; + } + + if (!is_gimple_val (rhs1) + || !is_gimple_val (rhs2) + || !is_gimple_val (rhs3)) + { + error ("invalid operands in ternary operation"); + return true; + } + + /* First handle operations that involve different types. */ + switch (rhs_code) + { + case WIDEN_MULT_PLUS_EXPR: + case WIDEN_MULT_MINUS_EXPR: + if ((!INTEGRAL_TYPE_P (rhs1_type) + && !FIXED_POINT_TYPE_P (rhs1_type)) + || !useless_type_conversion_p (rhs1_type, rhs2_type) + || !useless_type_conversion_p (lhs_type, rhs3_type) + || 2 * TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (lhs_type) + || TYPE_PRECISION (rhs1_type) != TYPE_PRECISION (rhs2_type)) + { + error ("type mismatch in widening multiply-accumulate expression"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + debug_generic_expr (rhs2_type); + debug_generic_expr (rhs3_type); + return true; + } + break; + + case FMA_EXPR: + if (!useless_type_conversion_p (lhs_type, rhs1_type) + || !useless_type_conversion_p (lhs_type, rhs2_type) + || !useless_type_conversion_p (lhs_type, rhs3_type)) + { + error ("type mismatch in fused multiply-add expression"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + debug_generic_expr (rhs2_type); + debug_generic_expr (rhs3_type); + return true; + } + break; + + default: + gcc_unreachable (); + } + return false; +} + /* Verify a gimple assignment statement STMT with a single rhs. Returns true if anything is wrong. */ @@ -3546,7 +3711,13 @@ verify_gimple_assign_single (gimple stmt) return true; } - if (!types_compatible_p (TREE_TYPE (op), TREE_TYPE (TREE_TYPE (rhs1))) + /* Technically there is no longer a need for matching types, but + gimple hygiene asks for this check. In LTO we can end up + combining incompatible units and thus end up with addresses + of globals that change their type to a common one. */ + if (!in_lto_p + && !types_compatible_p (TREE_TYPE (op), + TREE_TYPE (TREE_TYPE (rhs1))) && !one_pointer_to_useless_type_conversion_p (TREE_TYPE (rhs1), TREE_TYPE (op))) { @@ -3560,17 +3731,19 @@ verify_gimple_assign_single (gimple stmt) } /* tcc_reference */ + case INDIRECT_REF: + error ("INDIRECT_REF in gimple IL"); + return true; + case COMPONENT_REF: case BIT_FIELD_REF: - case INDIRECT_REF: - case ALIGN_INDIRECT_REF: - case MISALIGNED_INDIRECT_REF: case ARRAY_REF: case ARRAY_RANGE_REF: case VIEW_CONVERT_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: case TARGET_MEM_REF: + case MEM_REF: if (!is_gimple_reg (lhs) && is_gimple_reg_type (TREE_TYPE (lhs))) { @@ -3608,6 +3781,20 @@ verify_gimple_assign_single (gimple stmt) return res; case COND_EXPR: + if (!is_gimple_reg (lhs) + || (!is_gimple_reg (TREE_OPERAND (rhs1, 0)) + && !COMPARISON_CLASS_P (TREE_OPERAND (rhs1, 0))) + || (!is_gimple_reg (TREE_OPERAND (rhs1, 1)) + && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 1))) + || (!is_gimple_reg (TREE_OPERAND (rhs1, 2)) + && !is_gimple_min_invariant (TREE_OPERAND (rhs1, 2)))) + { + error ("invalid COND_EXPR in gimple assignment"); + debug_generic_stmt (rhs1); + return true; + } + return res; + case CONSTRUCTOR: case OBJ_TYPE_REF: case ASSERT_EXPR: @@ -3642,6 +3829,9 @@ verify_gimple_assign (gimple stmt) case GIMPLE_BINARY_RHS: return verify_gimple_assign_binary (stmt); + case GIMPLE_TERNARY_RHS: + return verify_gimple_assign_ternary (stmt); + default: gcc_unreachable (); } @@ -3669,12 +3859,14 @@ verify_gimple_return (gimple stmt) return true; } - if (!useless_type_conversion_p (restype, TREE_TYPE (op)) - /* ??? With C++ we can have the situation that the result - decl is a reference type while the return type is an aggregate. */ - && !(TREE_CODE (op) == RESULT_DECL - && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE - && useless_type_conversion_p (restype, TREE_TYPE (TREE_TYPE (op))))) + if ((TREE_CODE (op) == RESULT_DECL + && DECL_BY_REFERENCE (op)) + || (TREE_CODE (op) == SSA_NAME + && TREE_CODE (SSA_NAME_VAR (op)) == RESULT_DECL + && DECL_BY_REFERENCE (SSA_NAME_VAR (op)))) + op = TREE_TYPE (op); + + if (!useless_type_conversion_p (restype, TREE_TYPE (op))) { error ("invalid conversion in return statement"); debug_generic_stmt (restype); @@ -3735,7 +3927,7 @@ verify_gimple_phi (gimple stmt) if (TREE_CODE (gimple_phi_result (stmt)) != SSA_NAME) { - error ("Invalid PHI result"); + error ("invalid PHI result"); return true; } @@ -3747,13 +3939,13 @@ verify_gimple_phi (gimple stmt) || (!is_gimple_reg (gimple_phi_result (stmt)) && !is_gimple_addressable (arg))) { - error ("Invalid PHI argument"); + error ("invalid PHI argument"); debug_generic_stmt (arg); return true; } if (!useless_type_conversion_p (type, TREE_TYPE (arg))) { - error ("Incompatible types in PHI argument %u", i); + error ("incompatible types in PHI argument %u", i); debug_generic_stmt (type); debug_generic_stmt (TREE_TYPE (arg)); return true; @@ -3981,14 +4173,8 @@ verify_stmt (gimple_stmt_iterator *gsi) { if (!stmt_could_throw_p (stmt)) { - /* During IPA passes, ipa-pure-const sets nothrow flags on calls - and they are updated on statements only after fixup_cfg - is executed at beggining of expansion stage. */ - if (cgraph_state != CGRAPH_STATE_IPA_SSA) - { - error ("statement marked for throw, but doesn%'t"); - goto fail; - } + error ("statement marked for throw, but doesn%'t"); + goto fail; } else if (lp_nr > 0 && !last_in_block && stmt_can_throw_internal (stmt)) { @@ -4064,7 +4250,7 @@ verify_eh_throw_stmt_node (void **slot, void *data) if (!pointer_set_contains (visited, node->stmt)) { - error ("Dead STMT in EH table"); + error ("dead STMT in EH table"); debug_gimple_stmt (node->stmt); eh_error_found = true; } @@ -4074,7 +4260,7 @@ verify_eh_throw_stmt_node (void **slot, void *data) /* Verify the GIMPLE statements in every basic block. */ -void +DEBUG_FUNCTION void verify_stmts (void) { basic_block bb; @@ -4422,6 +4608,10 @@ gimple_verify_flow_info (void) } break; + case GIMPLE_CALL: + if (!gimple_call_builtin_p (stmt, BUILT_IN_RETURN)) + break; + /* ... fallthru ... */ case GIMPLE_RETURN: if (!single_succ_p (bb) || (single_succ_edge (bb)->flags @@ -5441,7 +5631,7 @@ replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map, if (SSA_VAR_P (t)) { new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t)); - f->local_decls = tree_cons (NULL_TREE, new_t, f->local_decls); + add_local_decl (f, new_t); } else { @@ -5695,21 +5885,6 @@ move_stmt_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, return NULL_TREE; } -/* Marks virtual operands of all statements in basic blocks BBS for - renaming. */ - -void -mark_virtual_ops_in_bb (basic_block bb) -{ - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - mark_virtual_ops_for_renaming (gsi_stmt (gsi)); - - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - mark_virtual_ops_for_renaming (gsi_stmt (gsi)); -} - /* Move basic block BB from function CFUN to function DEST_FN. The block is moved out of the original linked list and placed after block AFTER in the new list. Also, the block is removed from the @@ -5927,7 +6102,7 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map, { tree *tp, t; - for (tp = &BLOCK_VARS (block); *tp; tp = &TREE_CHAIN (*tp)) + for (tp = &BLOCK_VARS (block); *tp; tp = &DECL_CHAIN (*tp)) { t = *tp; if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != CONST_DECL) @@ -5940,7 +6115,7 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map, SET_DECL_VALUE_EXPR (t, DECL_VALUE_EXPR (*tp)); DECL_HAS_VALUE_EXPR_P (t) = 1; } - TREE_CHAIN (t) = TREE_CHAIN (*tp); + DECL_CHAIN (t) = DECL_CHAIN (*tp); *tp = t; } } @@ -6057,7 +6232,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, { eh_region region = NULL; - for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs, i, bb) region = find_outermost_region_in_block (saved_cfun, bb, region); init_eh_for_function (); @@ -6086,7 +6261,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, d.eh_map = eh_map; d.remap_decls_p = true; - for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs, i, bb) { /* No need to update edge counts on the last block. It has already been updated earlier when we detached the region from @@ -6151,7 +6326,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, } set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry); - for (i = 0; VEC_iterate (basic_block, dom_bbs, i, abb); i++) + FOR_EACH_VEC_ELT (basic_block, dom_bbs, i, abb) set_immediate_dominator (CDI_DOMINATORS, abb, bb); VEC_free (basic_block, heap, dom_bbs); @@ -6176,7 +6351,7 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, void dump_function_to_file (tree fn, FILE *file, int flags) { - tree arg, vars, var; + tree arg, var; struct function *dsf; bool ignore_topmost_bind = false, any_var = false; basic_block bb; @@ -6192,9 +6367,9 @@ dump_function_to_file (tree fn, FILE *file, int flags) print_generic_expr (file, arg, dump_flags); if (flags & TDF_VERBOSE) print_node (file, "", arg, 4); - if (TREE_CHAIN (arg)) + if (DECL_CHAIN (arg)) fprintf (file, ", "); - arg = TREE_CHAIN (arg); + arg = DECL_CHAIN (arg); } fprintf (file, ")\n"); @@ -6216,15 +6391,14 @@ dump_function_to_file (tree fn, FILE *file, int flags) /* When GIMPLE is lowered, the variables are no longer available in BIND_EXPRs, so display them separately. */ - if (cfun && cfun->decl == fn && cfun->local_decls) + if (cfun && cfun->decl == fn && !VEC_empty (tree, cfun->local_decls)) { + unsigned ix; ignore_topmost_bind = true; fprintf (file, "{\n"); - for (vars = cfun->local_decls; vars; vars = TREE_CHAIN (vars)) + FOR_EACH_LOCAL_DECL (cfun, ix, var) { - var = TREE_VALUE (vars); - print_generic_decl (file, var, flags); if (flags & TDF_VERBOSE) print_node (file, "", var, 4); @@ -6305,6 +6479,8 @@ dump_function_to_file (tree fn, FILE *file, int flags) fprintf (file, "}\n"); } + if (flags & TDF_ENUMERATE_LOCALS) + dump_enumerated_decls (file, flags); fprintf (file, "\n\n"); /* Restore CFUN. */ @@ -6314,7 +6490,7 @@ dump_function_to_file (tree fn, FILE *file, int flags) /* Dump FUNCTION_DECL FN to stderr using FLAGS (see TDF_* in tree.h) */ -void +DEBUG_FUNCTION void debug_function (tree fn, int flags) { dump_function_to_file (fn, stderr, flags); @@ -6455,7 +6631,7 @@ print_loops (FILE *file, int verbosity) /* Debugging loops structure at tree level, at some VERBOSITY level. */ -void +DEBUG_FUNCTION void debug_loops (int verbosity) { print_loops (stderr, verbosity); @@ -6463,7 +6639,7 @@ debug_loops (int verbosity) /* Print on stderr the code of LOOP, at some VERBOSITY level. */ -void +DEBUG_FUNCTION void debug_loop (struct loop *loop, int verbosity) { print_loop (stderr, loop, 0, verbosity); @@ -6472,7 +6648,7 @@ debug_loop (struct loop *loop, int verbosity) /* Print on stderr the code of loop number NUM, at some VERBOSITY level. */ -void +DEBUG_FUNCTION void debug_loop_num (unsigned num, int verbosity) { debug_loop (get_loop (num), verbosity); @@ -6486,7 +6662,7 @@ static bool gimple_block_ends_with_call_p (basic_block bb) { gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); - return is_gimple_call (gsi_stmt (gsi)); + return !gsi_end_p (gsi) && is_gimple_call (gsi_stmt (gsi)); } @@ -6587,7 +6763,7 @@ gimple_flow_call_edges_add (sbitmap blocks) if (check_last_block) { basic_block bb = EXIT_BLOCK_PTR->prev_bb; - gimple_stmt_iterator gsi = gsi_last_bb (bb); + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); gimple t = NULL; if (!gsi_end_p (gsi)) @@ -6621,7 +6797,7 @@ gimple_flow_call_edges_add (sbitmap blocks) if (blocks && !TEST_BIT (blocks, i)) continue; - gsi = gsi_last_bb (bb); + gsi = gsi_last_nondebug_bb (bb); if (!gsi_end_p (gsi)) { last_stmt = gsi_stmt (gsi); @@ -6667,39 +6843,6 @@ gimple_flow_call_edges_add (sbitmap blocks) return blocks_split; } -/* Purge dead abnormal call edges from basic block BB. */ - -bool -gimple_purge_dead_abnormal_call_edges (basic_block bb) -{ - bool changed = gimple_purge_dead_eh_edges (bb); - - if (cfun->has_nonlocal_label) - { - gimple stmt = last_stmt (bb); - edge_iterator ei; - edge e; - - if (!(stmt && stmt_can_make_abnormal_goto (stmt))) - for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) - { - if (e->flags & EDGE_ABNORMAL) - { - remove_edge (e); - changed = true; - } - else - ei_next (&ei); - } - - /* See gimple_purge_dead_eh_edges below. */ - if (changed) - free_dominance_info (CDI_DOMINATORS); - } - - return changed; -} - /* Removes edge E and all the blocks dominated by it, and updates dominance information. The IL in E->src needs to be updated separately. If dominance info is not available, only the edge E is removed.*/ @@ -6760,7 +6903,7 @@ remove_edge_and_dominated_blocks (edge e) else { bbs_to_remove = get_all_dominated_blocks (CDI_DOMINATORS, e->dest); - for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb) { FOR_EACH_EDGE (f, ei, bb->succs) { @@ -6768,7 +6911,7 @@ remove_edge_and_dominated_blocks (edge e) bitmap_set_bit (df, f->dest->index); } } - for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++) + FOR_EACH_VEC_ELT (basic_block, bbs_to_remove, i, bb) bitmap_clear_bit (df, bb->index); EXECUTE_IF_SET_IN_BITMAP (df, 0, i, bi) @@ -6853,6 +6996,8 @@ gimple_purge_dead_eh_edges (basic_block bb) return changed; } +/* Purge dead EH edges from basic block listed in BLOCKS. */ + bool gimple_purge_all_dead_eh_edges (const_bitmap blocks) { @@ -6874,6 +7019,59 @@ gimple_purge_all_dead_eh_edges (const_bitmap blocks) return changed; } +/* Purge dead abnormal call edges from basic block BB. */ + +bool +gimple_purge_dead_abnormal_call_edges (basic_block bb) +{ + bool changed = false; + edge e; + edge_iterator ei; + gimple stmt = last_stmt (bb); + + if (!cfun->has_nonlocal_label) + return false; + + if (stmt && stmt_can_make_abnormal_goto (stmt)) + return false; + + for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) + { + if (e->flags & EDGE_ABNORMAL) + { + remove_edge_and_dominated_blocks (e); + changed = true; + } + else + ei_next (&ei); + } + + return changed; +} + +/* Purge dead abnormal call edges from basic block listed in BLOCKS. */ + +bool +gimple_purge_all_dead_abnormal_call_edges (const_bitmap blocks) +{ + bool changed = false; + unsigned i; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i, bi) + { + basic_block bb = BASIC_BLOCK (i); + + /* Earlier gimple_purge_dead_abnormal_call_edges could have removed + this basic block already. */ + gcc_assert (bb || changed); + if (bb != NULL) + changed |= gimple_purge_dead_abnormal_call_edges (bb); + } + + return changed; +} + /* This function is called whenever a new edge is created or redirected. */ @@ -6980,7 +7178,7 @@ struct cfg_hooks gimple_cfg_hooks = { gimple_can_merge_blocks_p, /* can_merge_blocks_p */ gimple_merge_blocks, /* merge_blocks */ gimple_predict_edge, /* predict_edge */ - gimple_predicted_by_p, /* predicted_by_p */ + gimple_predicted_by_p, /* predicted_by_p */ gimple_can_duplicate_bb_p, /* can_duplicate_block_p */ gimple_duplicate_bb, /* duplicate_block */ gimple_split_edge, /* split_edge */ @@ -6988,7 +7186,7 @@ struct cfg_hooks gimple_cfg_hooks = { NULL, /* tidy_fallthru_edge */ gimple_block_ends_with_call_p,/* block_ends_with_call_p */ gimple_block_ends_with_condjump_p, /* block_ends_with_condjump_p */ - gimple_flow_call_edges_add, /* flow_call_edges_add */ + gimple_flow_call_edges_add, /* flow_call_edges_add */ gimple_execute_on_growing_pred, /* execute_on_growing_pred */ gimple_execute_on_shrinking_pred, /* execute_on_shrinking_pred */ gimple_duplicate_loop_to_header_edge, /* duplicate loop for trees */ @@ -7036,7 +7234,9 @@ split_critical_edges (void) gsi = gsi_last_bb (e->src); if (!gsi_end_p (gsi) && stmt_ends_bb_p (gsi_stmt (gsi)) - && gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN) + && (gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN + && !gimple_call_builtin_p (gsi_stmt (gsi), + BUILT_IN_RETURN))) split_edge (e); } } @@ -7134,7 +7334,8 @@ execute_warn_function_return (void) FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) { last = last_stmt (e->src); - if (gimple_code (last) == GIMPLE_RETURN + if ((gimple_code (last) == GIMPLE_RETURN + || gimple_call_builtin_p (last, BUILT_IN_RETURN)) && (location = gimple_location (last)) != UNKNOWN_LOCATION) break; } @@ -7218,22 +7419,24 @@ struct gimple_opt_pass pass_warn_function_return = static unsigned int execute_warn_function_noreturn (void) { - if (warn_missing_noreturn - && !TREE_THIS_VOLATILE (cfun->decl) - && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0 - && !lang_hooks.missing_noreturn_ok_p (cfun->decl)) - warning_at (DECL_SOURCE_LOCATION (cfun->decl), OPT_Wmissing_noreturn, - "function might be possible candidate " - "for attribute %"); + if (!TREE_THIS_VOLATILE (current_function_decl) + && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0) + warn_function_noreturn (current_function_decl); return 0; } +static bool +gate_warn_function_noreturn (void) +{ + return warn_suggest_attribute_noreturn; +} + struct gimple_opt_pass pass_warn_function_noreturn = { { GIMPLE_PASS, "*warn_function_noreturn", /* name */ - NULL, /* gate */ + gate_warn_function_noreturn, /* gate */ execute_warn_function_noreturn, /* execute */ NULL, /* sub */ NULL, /* next */