X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-cfg.c;h=4c7c0db12b6947e54c6c8a41e2d6a88ef7772965;hb=7ab76cecd643d0d098fb7293340afa0e2b5f9f37;hp=6bd8a06f8ad7ea0d468a9fc790178a1baf58cdc1;hpb=96d407e251a48310c804364ac77cc3181d6cd45a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 6bd8a06f8ad..4c7c0db12b6 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -1,5 +1,5 @@ /* Control flow functions for trees. - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Diego Novillo @@ -82,6 +82,14 @@ static struct cfg_stats_d cfg_stats; /* Nonzero if we found a computed goto while building basic blocks. */ static bool found_computed_goto; +/* Hash table to store last discriminator assigned for each locus. */ +struct locus_discrim_map +{ + location_t locus; + int discriminator; +}; +static htab_t discriminator_per_locus; + /* Basic blocks and flowgraphs. */ static void make_blocks (gimple_seq); static void factor_computed_gotos (void); @@ -91,6 +99,9 @@ static void make_edges (void); static void make_cond_expr_edges (basic_block); static void make_gimple_switch_edges (basic_block); static void make_goto_expr_edges (basic_block); +static unsigned int locus_map_hash (const void *); +static int locus_map_eq (const void *, const void *); +static void assign_discriminator (location_t, basic_block); static edge gimple_redirect_edge_and_branch (edge, basic_block); static edge gimple_try_redirect_by_replacing_jump (edge, basic_block); static unsigned int split_critical_edges (void); @@ -100,6 +111,7 @@ static inline bool stmt_starts_bb_p (gimple, gimple); static int gimple_verify_flow_info (void); static void gimple_make_forwarder_block (edge); static void gimple_cfg2vcg (FILE *); +static gimple first_non_label_stmt (basic_block); /* Flowgraph optimization and cleanup. */ static void gimple_merge_blocks (basic_block, basic_block); @@ -193,8 +205,11 @@ build_gimple_cfg (gimple_seq seq) group_case_labels (); /* Create the edges of the flowgraph. */ + discriminator_per_locus = htab_create (13, locus_map_hash, locus_map_eq, + free); make_edges (); cleanup_dead_labels (); + htab_delete (discriminator_per_locus); /* Debugging dumps. */ @@ -217,7 +232,15 @@ build_gimple_cfg (gimple_seq seq) static unsigned int execute_build_cfg (void) { - build_gimple_cfg (gimple_body (current_function_decl)); + gimple_seq body = gimple_body (current_function_decl); + + build_gimple_cfg (body); + gimple_set_body (current_function_decl, NULL); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Scope blocks:\n"); + dump_scope_blocks (dump_file, dump_flags); + } return 0; } @@ -306,7 +329,7 @@ factor_computed_gotos (void) /* Build a label for the new block which will contain the factored computed goto. */ - factored_label_decl = create_artificial_label (); + factored_label_decl = create_artificial_label (UNKNOWN_LOCATION); factored_computed_goto_label = gimple_build_label (factored_label_decl); gsi_insert_after (&new_gsi, factored_computed_goto_label, @@ -367,7 +390,29 @@ make_blocks (gimple_seq seq) /* If STMT is a basic block terminator, set START_NEW_BLOCK for the next iteration. */ if (stmt_ends_bb_p (stmt)) - start_new_block = true; + { + /* If the stmt can make abnormal goto use a new temporary + for the assignment to the LHS. This makes sure the old value + of the LHS is available on the abnormal edge. Otherwise + we will end up with overlapping life-ranges for abnormal + SSA names. */ + if (gimple_has_lhs (stmt) + && stmt_can_make_abnormal_goto (stmt) + && is_gimple_reg_type (TREE_TYPE (gimple_get_lhs (stmt)))) + { + tree lhs = gimple_get_lhs (stmt); + tree tmp = create_tmp_var (TREE_TYPE (lhs), NULL); + gimple s = gimple_build_assign (lhs, tmp); + gimple_set_location (s, gimple_location (stmt)); + gimple_set_block (s, gimple_block (stmt)); + gimple_set_lhs (stmt, tmp); + if (TREE_CODE (TREE_TYPE (tmp)) == COMPLEX_TYPE + || TREE_CODE (TREE_TYPE (tmp)) == VECTOR_TYPE) + DECL_GIMPLE_REG_P (tmp) = 1; + gsi_insert_after (&i, s, GSI_SAME_STMT); + } + start_new_block = true; + } gsi_next (&i); first_stmt_of_seq = false; @@ -620,7 +665,11 @@ make_edges (void) fallthru = true; if (fallthru) - make_edge (bb, bb->next_bb, EDGE_FALLTHRU); + { + make_edge (bb, bb->next_bb, EDGE_FALLTHRU); + if (last) + assign_discriminator (gimple_location (last), bb->next_bb); + } } if (root_omp_region) @@ -630,6 +679,91 @@ make_edges (void) fold_cond_expr_cond (); } +/* Trivial hash function for a location_t. ITEM is a pointer to + a hash table entry that maps a location_t to a discriminator. */ + +static unsigned int +locus_map_hash (const void *item) +{ + return ((const struct locus_discrim_map *) item)->locus; +} + +/* Equality function for the locus-to-discriminator map. VA and VB + point to the two hash table entries to compare. */ + +static int +locus_map_eq (const void *va, const void *vb) +{ + const struct locus_discrim_map *a = (const struct locus_discrim_map *) va; + const struct locus_discrim_map *b = (const struct locus_discrim_map *) vb; + return a->locus == b->locus; +} + +/* Find the next available discriminator value for LOCUS. The + discriminator distinguishes among several basic blocks that + share a common locus, allowing for more accurate sample-based + profiling. */ + +static int +next_discriminator_for_locus (location_t locus) +{ + struct locus_discrim_map item; + struct locus_discrim_map **slot; + + item.locus = locus; + item.discriminator = 0; + slot = (struct locus_discrim_map **) + htab_find_slot_with_hash (discriminator_per_locus, (void *) &item, + (hashval_t) locus, INSERT); + gcc_assert (slot); + if (*slot == HTAB_EMPTY_ENTRY) + { + *slot = XNEW (struct locus_discrim_map); + gcc_assert (*slot); + (*slot)->locus = locus; + (*slot)->discriminator = 0; + } + (*slot)->discriminator++; + return (*slot)->discriminator; +} + +/* Return TRUE if LOCUS1 and LOCUS2 refer to the same source line. */ + +static bool +same_line_p (location_t locus1, location_t locus2) +{ + expanded_location from, to; + + if (locus1 == locus2) + return true; + + from = expand_location (locus1); + to = expand_location (locus2); + + if (from.line != to.line) + return false; + if (from.file == to.file) + return true; + return (from.file != NULL + && to.file != NULL + && strcmp (from.file, to.file) == 0); +} + +/* Assign a unique discriminator value to block BB if it begins at the same + LOCUS as its predecessor block. */ + +static void +assign_discriminator (location_t locus, basic_block bb) +{ + gimple to_stmt; + + if (locus == 0 || bb->discriminator != 0) + return; + + to_stmt = first_non_label_stmt (bb); + if (to_stmt && same_line_p (locus, gimple_location (to_stmt))) + bb->discriminator = next_discriminator_for_locus (locus); +} /* Create the edges for a GIMPLE_COND starting at block BB. */ @@ -641,10 +775,13 @@ make_cond_expr_edges (basic_block bb) basic_block then_bb, else_bb; tree then_label, else_label; edge e; + location_t entry_locus; gcc_assert (entry); gcc_assert (gimple_code (entry) == GIMPLE_COND); + entry_locus = gimple_location (entry); + /* Entry basic blocks for each component. */ then_label = gimple_cond_true_label (entry); else_label = gimple_cond_false_label (entry); @@ -654,10 +791,18 @@ make_cond_expr_edges (basic_block bb) else_stmt = first_stmt (else_bb); e = make_edge (bb, then_bb, EDGE_TRUE_VALUE); + assign_discriminator (entry_locus, then_bb); e->goto_locus = gimple_location (then_stmt); + if (e->goto_locus) + e->goto_block = gimple_block (then_stmt); e = make_edge (bb, else_bb, EDGE_FALSE_VALUE); if (e) - e->goto_locus = gimple_location (else_stmt); + { + assign_discriminator (entry_locus, else_bb); + e->goto_locus = gimple_location (else_stmt); + if (e->goto_locus) + e->goto_block = gimple_block (else_stmt); + } /* We do not need the labels anymore. */ gimple_cond_set_true_label (entry, NULL_TREE); @@ -763,8 +908,11 @@ static void make_gimple_switch_edges (basic_block bb) { gimple entry = last_stmt (bb); + location_t entry_locus; size_t i, n; + entry_locus = gimple_location (entry); + n = gimple_switch_num_labels (entry); for (i = 0; i < n; ++i) @@ -772,6 +920,7 @@ make_gimple_switch_edges (basic_block bb) tree lab = CASE_LABEL (gimple_switch_label (entry, i)); basic_block label_bb = label_to_block (lab); make_edge (bb, label_bb, 0); + assign_discriminator (entry_locus, label_bb); } } @@ -844,8 +993,12 @@ make_goto_expr_edges (basic_block bb) if (simple_goto_p (goto_t)) { tree dest = gimple_goto_dest (goto_t); - edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU); + basic_block label_bb = label_to_block (dest); + edge e = make_edge (bb, label_bb, EDGE_FALLTHRU); e->goto_locus = gimple_location (goto_t); + assign_discriminator (e->goto_locus, label_bb); + if (e->goto_locus) + e->goto_block = gimple_block (goto_t); gsi_remove (&last, true); return; } @@ -879,7 +1032,7 @@ static struct label_record /* Callback for for_each_eh_region. Helper for cleanup_dead_labels. */ static void -update_eh_label (struct eh_region *region) +update_eh_label (struct eh_region_d *region) { tree old_label = get_eh_region_tree_label (region); if (old_label) @@ -1174,7 +1327,7 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b) if (!single_succ_p (a)) return false; - if (single_succ_edge (a)->flags & EDGE_ABNORMAL) + if (single_succ_edge (a)->flags & (EDGE_ABNORMAL | EDGE_EH)) return false; if (single_succ (a) != b) @@ -1251,9 +1404,6 @@ replace_uses_by (tree name, tree val) FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name) { - if (gimple_code (stmt) != GIMPLE_PHI) - push_stmt_changes (&stmt); - FOR_EACH_IMM_USE_ON_STMT (use, imm_iter) { replace_exp (use, val); @@ -1280,7 +1430,7 @@ replace_uses_by (tree name, tree val) if (cfgcleanup_altered_bbs) bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index); - /* FIXME. This should go in pop_stmt_changes. */ + /* FIXME. This should go in update_stmt. */ for (i = 0; i < gimple_num_ops (stmt); i++) { tree op = gimple_op (stmt, i); @@ -1292,8 +1442,7 @@ replace_uses_by (tree name, tree val) } maybe_clean_or_replace_eh_stmt (stmt, stmt); - - pop_stmt_changes (&stmt); + update_stmt (stmt); } } @@ -1422,7 +1571,7 @@ gimple_merge_blocks (basic_block a, basic_block b) /* Return the one of two successors of BB that is not reachable by a - reached by a complex edge, if there is one. Else, return BB. We use + complex edge, if there is one. Else, return BB. We use this in optimizations that use post-dominators for their heuristics, to catch the cases in C++ where function calls are involved. */ @@ -1536,7 +1685,8 @@ remove_useless_stmts_cond (gimple_stmt_iterator *gsi, struct rus_data *data) gimple stmt = gsi_stmt (*gsi); /* The folded result must still be a conditional statement. */ - fold_stmt_inplace (stmt); + fold_stmt (gsi); + gcc_assert (gsi_stmt (*gsi) == stmt); data->may_branch = true; @@ -1780,9 +1930,21 @@ remove_useless_stmts_bind (gimple_stmt_iterator *gsi, struct rus_data *data ATTR || (TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) != FUNCTION_DECL))) { - gsi_insert_seq_before (gsi, body_seq, GSI_SAME_STMT); - gsi_remove (gsi, false); - data->repeat = true; + tree var = NULL_TREE; + /* Even if there are no gimple_bind_vars, there might be other + decls in BLOCK_VARS rendering the GIMPLE_BIND not useless. */ + if (block && !BLOCK_NUM_NONLOCALIZED_VARS (block)) + for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var)) + if (TREE_CODE (var) == IMPORTED_DECL) + break; + if (var || (block && BLOCK_NUM_NONLOCALIZED_VARS (block))) + gsi_next (gsi); + else + { + gsi_insert_seq_before (gsi, body_seq, GSI_SAME_STMT); + gsi_remove (gsi, false); + data->repeat = true; + } } else gsi_next (gsi); @@ -2021,6 +2183,11 @@ remove_useless_stmts (void) remove_useless_stmts_1 (&gsi, &data); } while (data.repeat); + +#ifdef ENABLE_TYPES_CHECKING + verify_types_in_gimple_seq (gimple_body (current_function_decl)); +#endif + return 0; } @@ -2035,7 +2202,7 @@ struct gimple_opt_pass pass_remove_useless_stmts = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ PROP_gimple_any, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -2049,14 +2216,9 @@ struct gimple_opt_pass pass_remove_useless_stmts = static void remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb) { - gimple_stmt_iterator gsi; - /* Since this block is no longer reachable, we can just delete all of its PHI nodes. */ - for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); ) - remove_phi_node (&gsi, true); - - set_phi_nodes (bb, NULL); + remove_phi_nodes (bb); /* Remove edges to BB's successors. */ while (EDGE_COUNT (bb->succs) > 0) @@ -2643,6 +2805,17 @@ first_stmt (basic_block bb) return !gsi_end_p (i) ? gsi_stmt (i) : NULL; } +/* Return the first non-label statement in basic block BB. */ + +static gimple +first_non_label_stmt (basic_block bb) +{ + gimple_stmt_iterator i = gsi_start_bb (bb); + while (!gsi_end_p (i) && gimple_code (gsi_stmt (i)) == GIMPLE_LABEL) + gsi_next (&i); + return !gsi_end_p (i) ? gsi_stmt (i) : NULL; +} + /* Return the last statement in basic block BB. */ gimple @@ -2787,6 +2960,15 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) } break; + case INDIRECT_REF: + x = TREE_OPERAND (t, 0); + if (!is_gimple_reg (x) && !is_gimple_min_invariant (x)) + { + error ("Indirect reference's operand is not a register or a constant."); + return x; + } + break; + case ASSERT_EXPR: x = fold (ASSERT_EXPR_COND (t)); if (x == boolean_false_node) @@ -2797,14 +2979,8 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) break; case MODIFY_EXPR: - x = TREE_OPERAND (t, 0); - if (TREE_CODE (x) == BIT_FIELD_REF - && is_gimple_reg (TREE_OPERAND (x, 0))) - { - error ("GIMPLE register modified with BIT_FIELD_REF"); - return t; - } - break; + error ("MODIFY_EXPR not expected while having tuples."); + return *tp; case ADDR_EXPR: { @@ -2841,13 +3017,20 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) x = TREE_OPERAND (x, 0)) ; - if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL) + 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; } @@ -3032,14 +3215,17 @@ verify_types_in_gimple_min_lval (tree expr) if (is_gimple_id (expr)) return false; - if (TREE_CODE (expr) != INDIRECT_REF - && TREE_CODE (expr) != ALIGN_INDIRECT_REF - && TREE_CODE (expr) != MISALIGNED_INDIRECT_REF) + if (!INDIRECT_REF_P (expr) + && TREE_CODE (expr) != TARGET_MEM_REF) { error ("invalid expression for min lvalue"); return true; } + /* TARGET_MEM_REFs are strange beasts. */ + if (TREE_CODE (expr) == TARGET_MEM_REF) + return false; + op = TREE_OPERAND (expr, 0); if (!is_gimple_val (op)) { @@ -3059,11 +3245,12 @@ verify_types_in_gimple_min_lval (tree expr) return false; } -/* Verify if EXPR is a valid GIMPLE reference expression. Returns true +/* Verify if EXPR is a valid GIMPLE reference expression. If + REQUIRE_LVALUE is true verifies it is an lvalue. Returns true if there is an error, otherwise false. */ static bool -verify_types_in_gimple_reference (tree expr) +verify_types_in_gimple_reference (tree expr, bool require_lvalue) { while (handled_component_p (expr)) { @@ -3128,11 +3315,15 @@ verify_types_in_gimple_reference (tree expr) /* For VIEW_CONVERT_EXPRs which are allowed here, too, there is nothing to verify. Gross mismatches at most invoke undefined behavior. */ + if (TREE_CODE (expr) == VIEW_CONVERT_EXPR + && !handled_component_p (op)) + return false; expr = op; } - return verify_types_in_gimple_min_lval (expr); + return ((require_lvalue || !is_gimple_min_invariant (expr)) + && verify_types_in_gimple_min_lval (expr)); } /* Returns true if there is one pointer type in TYPE_POINTER_TO (SRC_OBJ) @@ -3165,107 +3356,139 @@ valid_fixed_convert_types_p (tree type1, tree type2) || FIXED_POINT_TYPE_P (type2))); } -/* Verify that OP is a valid GIMPLE operand. Return true if there is - an error, false otherwise. */ - -static bool -verify_types_in_gimple_op (tree op) -{ - if (!is_gimple_val (op) && !is_gimple_lvalue (op)) - { - error ("Invalid GIMPLE operand"); - debug_generic_expr (op); - return true; - } - - return false; -} - - /* Verify the contents of a GIMPLE_CALL STMT. Returns true when there is a problem, otherwise false. */ static bool -verify_types_in_gimple_call (gimple stmt) +verify_gimple_call (gimple stmt) { - bool failed = false; - unsigned int i; - tree fn; + tree fn = gimple_call_fn (stmt); + tree fntype; - if (gimple_call_lhs (stmt)) - failed |= verify_types_in_gimple_op (gimple_call_lhs (stmt)); + if (!POINTER_TYPE_P (TREE_TYPE (fn)) + || (TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != FUNCTION_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (fn))) != METHOD_TYPE)) + { + error ("non-function in gimple call"); + return true; + } - fn = gimple_call_fn (stmt); - if (TREE_CODE (fn) != OBJ_TYPE_REF - && verify_types_in_gimple_op (fn)) - failed = true; + if (gimple_call_lhs (stmt) + && !is_gimple_lvalue (gimple_call_lhs (stmt))) + { + error ("invalid LHS in gimple call"); + return true; + } - if (gimple_call_chain (stmt)) - failed |= verify_types_in_gimple_op (gimple_call_chain (stmt)); + fntype = TREE_TYPE (TREE_TYPE (fn)); + if (gimple_call_lhs (stmt) + && !useless_type_conversion_p (TREE_TYPE (gimple_call_lhs (stmt)), + TREE_TYPE (fntype)) + /* ??? At least C++ misses conversions at assignments from + void * call results. + ??? Java is completely off. Especially with functions + returning java.lang.Object. + For now simply allow arbitrary pointer type conversions. */ + && !(POINTER_TYPE_P (TREE_TYPE (gimple_call_lhs (stmt))) + && POINTER_TYPE_P (TREE_TYPE (fntype)))) + { + error ("invalid conversion in gimple call"); + debug_generic_stmt (TREE_TYPE (gimple_call_lhs (stmt))); + debug_generic_stmt (TREE_TYPE (fntype)); + return true; + } - for (i = 0; i < gimple_call_num_args (stmt); i++) - failed |= verify_types_in_gimple_op (gimple_call_arg (stmt,i)); + /* ??? 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 + unit-at-a-time we have a chance to fix this. */ - return failed; + return false; } - -/* Verify the contents of a GIMPLE_COND STMT. Returns true when there - is a problem, otherwise false. */ +/* Verifies the gimple comparison with the result type TYPE and + the operands OP0 and OP1. */ static bool -verify_types_in_gimple_cond (gimple stmt) +verify_gimple_comparison (tree type, tree op0, tree op1) { - bool failed = false; - - failed |= verify_types_in_gimple_op (gimple_cond_lhs (stmt)); - failed |= verify_types_in_gimple_op (gimple_cond_rhs (stmt)); - failed |= verify_types_in_gimple_op (gimple_cond_true_label (stmt)); - failed |= verify_types_in_gimple_op (gimple_cond_false_label (stmt)); + tree op0_type = TREE_TYPE (op0); + tree op1_type = TREE_TYPE (op1); - return failed; -} + if (!is_gimple_val (op0) || !is_gimple_val (op1)) + { + error ("invalid operands in gimple comparison"); + return true; + } + /* For comparisons we do not have the operations type as the + effective type the comparison is carried out in. Instead + we require that either the first operand is trivially + convertible into the second, or the other way around. + The resulting type of a comparison may be any integral type. + Because we special-case pointers to void we allow + comparisons of pointers with the same mode as well. */ + if ((!useless_type_conversion_p (op0_type, op1_type) + && !useless_type_conversion_p (op1_type, op0_type) + && (!POINTER_TYPE_P (op0_type) + || !POINTER_TYPE_P (op1_type) + || TYPE_MODE (op0_type) != TYPE_MODE (op1_type))) + || !INTEGRAL_TYPE_P (type)) + { + error ("type mismatch in comparison expression"); + debug_generic_expr (type); + debug_generic_expr (op0_type); + debug_generic_expr (op1_type); + return true; + } -/* Verify the contents of a GIMPLE_ASSIGN STMT. Returns true when there - is a problem, otherwise false. + return false; +} - Verify that the types of the LHS and the RHS operands are - compatible. This verification largely depends on what kind of - operation is done on the RHS of the assignment. It is not always - the case that all the types of the operands must match (e.g., 'a = - (unsigned long) b' or 'ptr = ptr + 1'). */ +/* Verify a gimple assignment statement STMT with an unary rhs. + Returns true if anything is wrong. */ static bool -verify_types_in_gimple_assign (gimple stmt) +verify_gimple_assign_unary (gimple stmt) { enum tree_code rhs_code = gimple_assign_rhs_code (stmt); tree lhs = gimple_assign_lhs (stmt); - tree rhs1 = gimple_assign_rhs1 (stmt); - tree rhs2 = (gimple_num_ops (stmt) == 3) ? gimple_assign_rhs2 (stmt) : NULL; tree lhs_type = TREE_TYPE (lhs); + tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs1_type = TREE_TYPE (rhs1); - tree rhs2_type = (rhs2) ? TREE_TYPE (rhs2) : NULL; - /* Special codes we cannot handle via their class. */ + if (!is_gimple_reg (lhs) + && !(optimize == 0 + && TREE_CODE (lhs_type) == COMPLEX_TYPE)) + { + error ("non-register as LHS of unary operation"); + return true; + } + + if (!is_gimple_val (rhs1)) + { + error ("invalid operand in unary operation"); + return true; + } + + /* First handle conversions. */ switch (rhs_code) { CASE_CONVERT: { - if (!is_gimple_val (rhs1)) - { - error ("invalid operand in conversion"); - return true; - } - /* Allow conversions between integral types and pointers only if - there is no sign or zero extension involved. */ - if (((POINTER_TYPE_P (lhs_type) && INTEGRAL_TYPE_P (rhs1_type)) - || (POINTER_TYPE_P (rhs1_type) && INTEGRAL_TYPE_P (lhs_type))) - && (TYPE_PRECISION (lhs_type) == TYPE_PRECISION (rhs1_type) - /* For targets were the precision of sizetype doesn't - match that of pointers we need the following. */ - || lhs_type == sizetype || rhs1_type == sizetype)) + there is no sign or zero extension involved. + For targets were the precision of sizetype doesn't match that + of pointers we need to allow arbitrary conversions from and + to sizetype. */ + if ((POINTER_TYPE_P (lhs_type) + && INTEGRAL_TYPE_P (rhs1_type) + && (TYPE_PRECISION (lhs_type) >= TYPE_PRECISION (rhs1_type) + || rhs1_type == sizetype)) + || (POINTER_TYPE_P (rhs1_type) + && INTEGRAL_TYPE_P (lhs_type) + && (TYPE_PRECISION (rhs1_type) >= TYPE_PRECISION (lhs_type) + || lhs_type == sizetype))) return false; /* Allow conversion from integer to offset type and vice versa. */ @@ -3290,12 +3513,6 @@ verify_types_in_gimple_assign (gimple stmt) case FIXED_CONVERT_EXPR: { - if (!is_gimple_val (rhs1)) - { - error ("invalid operand in conversion"); - return true; - } - if (!valid_fixed_convert_types_p (lhs_type, rhs1_type) && !valid_fixed_convert_types_p (rhs1_type, lhs_type)) { @@ -3310,12 +3527,6 @@ verify_types_in_gimple_assign (gimple stmt) case FLOAT_EXPR: { - if (!is_gimple_val (rhs1)) - { - error ("invalid operand in int to float conversion"); - return true; - } - if (!INTEGRAL_TYPE_P (rhs1_type) || !SCALAR_FLOAT_TYPE_P (lhs_type)) { error ("invalid types in conversion to floating point"); @@ -3329,12 +3540,6 @@ verify_types_in_gimple_assign (gimple stmt) case FIX_TRUNC_EXPR: { - if (!is_gimple_val (rhs1)) - { - error ("invalid operand in float to int conversion"); - return true; - } - if (!INTEGRAL_TYPE_P (lhs_type) || !SCALAR_FLOAT_TYPE_P (rhs1_type)) { error ("invalid types in conversion to integer"); @@ -3346,18 +3551,79 @@ verify_types_in_gimple_assign (gimple stmt) return false; } + case VEC_UNPACK_HI_EXPR: + case VEC_UNPACK_LO_EXPR: + case REDUC_MAX_EXPR: + case REDUC_MIN_EXPR: + case REDUC_PLUS_EXPR: + case VEC_UNPACK_FLOAT_HI_EXPR: + case VEC_UNPACK_FLOAT_LO_EXPR: + /* FIXME. */ + return false; + + case TRUTH_NOT_EXPR: + case NEGATE_EXPR: + case ABS_EXPR: + case BIT_NOT_EXPR: + case PAREN_EXPR: + case NON_LVALUE_EXPR: + case CONJ_EXPR: + break; + + default: + gcc_unreachable (); + } + + /* For the remaining codes assert there is no conversion involved. */ + if (!useless_type_conversion_p (lhs_type, rhs1_type)) + { + error ("non-trivial conversion in unary operation"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + return true; + } + + return false; +} + +/* Verify a gimple assignment statement STMT with a binary rhs. + Returns true if anything is wrong. */ + +static bool +verify_gimple_assign_binary (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); + + if (!is_gimple_reg (lhs) + && !(optimize == 0 + && TREE_CODE (lhs_type) == COMPLEX_TYPE)) + { + error ("non-register as LHS of binary operation"); + return true; + } + + if (!is_gimple_val (rhs1) + || !is_gimple_val (rhs2)) + { + error ("invalid operands in binary operation"); + return true; + } + + /* First handle operations that involve different types. */ + switch (rhs_code) + { case COMPLEX_EXPR: { - if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2)) - { - error ("invalid operands in complex expression"); - return true; - } - - if (!TREE_CODE (lhs_type) == COMPLEX_TYPE - || !(TREE_CODE (rhs1_type) == INTEGER_TYPE + if (TREE_CODE (lhs_type) != COMPLEX_TYPE + || !(INTEGRAL_TYPE_P (rhs1_type) || SCALAR_FLOAT_TYPE_P (rhs1_type)) - || !(TREE_CODE (rhs2_type) == INTEGER_TYPE + || !(INTEGRAL_TYPE_P (rhs2_type) || SCALAR_FLOAT_TYPE_P (rhs2_type))) { error ("type mismatch in complex expression"); @@ -3370,39 +3636,96 @@ verify_types_in_gimple_assign (gimple stmt) return false; } - case CONSTRUCTOR: - { - /* In this context we know that we are on the RHS of an - assignment, so CONSTRUCTOR operands are OK. */ - /* FIXME: verify constructor arguments. */ - return false; - } - case LSHIFT_EXPR: case RSHIFT_EXPR: case LROTATE_EXPR: case RROTATE_EXPR: { - if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2)) + /* Shifts and rotates are ok on integral types, fixed point + types and integer vector types. */ + 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 (rhs2_type) + /* Vector shifts of vectors are also ok. */ + && !(TREE_CODE (rhs1_type) == VECTOR_TYPE + && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE + && TREE_CODE (rhs2_type) == VECTOR_TYPE + && TREE_CODE (TREE_TYPE (rhs2_type)) == INTEGER_TYPE)) + || !useless_type_conversion_p (lhs_type, rhs1_type)) { - error ("invalid operands in shift expression"); + error ("type mismatch in shift expression"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + debug_generic_expr (rhs2_type); return true; } - if (!TREE_CODE (rhs1_type) == INTEGER_TYPE + return false; + } + + case VEC_LSHIFT_EXPR: + case VEC_RSHIFT_EXPR: + { + if (TREE_CODE (rhs1_type) != VECTOR_TYPE + || !(INTEGRAL_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) + && (TREE_CODE (rhs2_type) != VECTOR_TYPE + || !INTEGRAL_TYPE_P (TREE_TYPE (rhs2_type)))) || !useless_type_conversion_p (lhs_type, rhs1_type)) { - error ("type mismatch in shift expression"); + error ("type mismatch in vector shift expression"); debug_generic_expr (lhs_type); debug_generic_expr (rhs1_type); debug_generic_expr (rhs2_type); return true; } + /* For shifting a vector of floating point components we + only allow shifting by a constant multiple of the element size. */ + if (SCALAR_FLOAT_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))))) + { + error ("non-element sized vector shift of floating point vector"); + return true; + } return false; } case PLUS_EXPR: + { + /* We use regular PLUS_EXPR for vectors. + ??? This just makes the checker happy and may not be what is + intended. */ + if (TREE_CODE (lhs_type) == VECTOR_TYPE + && POINTER_TYPE_P (TREE_TYPE (lhs_type))) + { + if (TREE_CODE (rhs1_type) != VECTOR_TYPE + || TREE_CODE (rhs2_type) != VECTOR_TYPE) + { + error ("invalid non-vector operands to vector valued plus"); + return true; + } + lhs_type = TREE_TYPE (lhs_type); + rhs1_type = TREE_TYPE (rhs1_type); + rhs2_type = TREE_TYPE (rhs2_type); + /* PLUS_EXPR is commutative, so we might end up canonicalizing + the pointer to 2nd place. */ + if (POINTER_TYPE_P (rhs2_type)) + { + tree tem = rhs1_type; + rhs1_type = rhs2_type; + rhs2_type = tem; + } + goto do_pointer_plus_expr_check; + } + } + /* Fallthru. */ case MINUS_EXPR: { if (POINTER_TYPE_P (lhs_type) @@ -3419,11 +3742,7 @@ verify_types_in_gimple_assign (gimple stmt) case POINTER_PLUS_EXPR: { - if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2)) - { - error ("invalid operands in pointer plus expression"); - return true; - } +do_pointer_plus_expr_check: if (!POINTER_TYPE_P (rhs1_type) || !useless_type_conversion_p (lhs_type, rhs1_type) || !useless_type_conversion_p (sizetype, rhs2_type)) @@ -3438,30 +3757,6 @@ verify_types_in_gimple_assign (gimple stmt) return false; } - case ADDR_EXPR: - { - tree op = TREE_OPERAND (rhs1, 0); - if (!is_gimple_addressable (op)) - { - error ("invalid operand in unary expression"); - return true; - } - - if (!one_pointer_to_useless_type_conversion_p (lhs_type, TREE_TYPE (op)) - /* FIXME: a longstanding wart, &a == &a[0]. */ - && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE - || !one_pointer_to_useless_type_conversion_p (lhs_type, - TREE_TYPE (TREE_TYPE (op))))) - { - error ("type mismatch in address expression"); - debug_generic_stmt (lhs_type); - debug_generic_stmt (TYPE_POINTER_TO (TREE_TYPE (op))); - return true; - } - - return verify_types_in_gimple_reference (TREE_OPERAND (rhs1, 0)); - } - case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: gcc_unreachable (); @@ -3470,12 +3765,6 @@ verify_types_in_gimple_assign (gimple stmt) case TRUTH_OR_EXPR: case TRUTH_XOR_EXPR: { - if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2)) - { - error ("invalid operands in truth expression"); - return true; - } - /* We allow any kind of integral typed argument and result. */ if (!INTEGRAL_TYPE_P (rhs1_type) || !INTEGRAL_TYPE_P (rhs2_type) @@ -3491,162 +3780,282 @@ verify_types_in_gimple_assign (gimple stmt) return false; } - case TRUTH_NOT_EXPR: + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case UNORDERED_EXPR: + case ORDERED_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + case LTGT_EXPR: + /* Comparisons are also binary, but the result type is not + connected to the operand types. */ + return verify_gimple_comparison (lhs_type, rhs1, rhs2); + + case WIDEN_SUM_EXPR: + case WIDEN_MULT_EXPR: + case VEC_WIDEN_MULT_HI_EXPR: + case VEC_WIDEN_MULT_LO_EXPR: + case VEC_PACK_TRUNC_EXPR: + case VEC_PACK_SAT_EXPR: + case VEC_PACK_FIX_TRUNC_EXPR: + case VEC_EXTRACT_EVEN_EXPR: + case VEC_EXTRACT_ODD_EXPR: + case VEC_INTERLEAVE_HIGH_EXPR: + case VEC_INTERLEAVE_LOW_EXPR: + /* FIXME. */ + return false; + + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + /* Continue with generic binary expression handling. */ + break; + + default: + gcc_unreachable (); + } + + if (!useless_type_conversion_p (lhs_type, rhs1_type) + || !useless_type_conversion_p (lhs_type, rhs2_type)) + { + error ("type mismatch in binary expression"); + debug_generic_stmt (lhs_type); + debug_generic_stmt (rhs1_type); + debug_generic_stmt (rhs2_type); + return true; + } + + return false; +} + +/* Verify a gimple assignment statement STMT with a single rhs. + Returns true if anything is wrong. */ + +static bool +verify_gimple_assign_single (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); + bool res = false; + + if (!useless_type_conversion_p (lhs_type, rhs1_type)) + { + error ("non-trivial conversion at assignment"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + return true; + } + + if (handled_component_p (lhs)) + res |= verify_types_in_gimple_reference (lhs, true); + + /* Special codes we cannot handle via their class. */ + switch (rhs_code) + { + case ADDR_EXPR: { - if (!is_gimple_val (rhs1)) + tree op = TREE_OPERAND (rhs1, 0); + if (!is_gimple_addressable (op)) { - error ("invalid operand in unary not"); + error ("invalid operand in unary expression"); return true; } - /* For TRUTH_NOT_EXPR we can have any kind of integral - typed arguments and results. */ - if (!INTEGRAL_TYPE_P (rhs1_type) - || !INTEGRAL_TYPE_P (lhs_type)) + if (!one_pointer_to_useless_type_conversion_p (lhs_type, + TREE_TYPE (op))) { - error ("type mismatch in not expression"); - debug_generic_expr (lhs_type); - debug_generic_expr (rhs1_type); + error ("type mismatch in address expression"); + debug_generic_stmt (lhs_type); + debug_generic_stmt (TYPE_POINTER_TO (TREE_TYPE (op))); return true; } - return false; + return verify_types_in_gimple_reference (op, true); } - /* After gimplification we should not have any of these. */ - case ASM_EXPR: - case BIND_EXPR: - case CALL_EXPR: - case COND_EXPR: - case TREE_LIST: - case COMPOUND_EXPR: - case MODIFY_EXPR: - case INIT_EXPR: - case GOTO_EXPR: - case LABEL_EXPR: - case RETURN_EXPR: - case TRY_FINALLY_EXPR: - case TRY_CATCH_EXPR: - case EH_FILTER_EXPR: - case STATEMENT_LIST: - { - error ("tree node that should already be gimple."); - return true; - } - - case OBJ_TYPE_REF: - /* FIXME. */ - return false; - - default:; - } - - /* Generic handling via classes. */ - switch (TREE_CODE_CLASS (rhs_code)) - { - case tcc_exceptional: /* for SSA_NAME */ - case tcc_unary: - if (!useless_type_conversion_p (lhs_type, rhs1_type)) - { - error ("non-trivial conversion at assignment"); - debug_generic_expr (lhs_type); - debug_generic_expr (rhs1_type); - return true; - } - break; - - case tcc_binary: - if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2)) - { - error ("invalid operands in binary expression"); - return true; - } - if (!useless_type_conversion_p (lhs_type, rhs1_type) - || !useless_type_conversion_p (lhs_type, rhs2_type)) + /* tcc_reference */ + 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: + if (!is_gimple_reg (lhs) + && is_gimple_reg_type (TREE_TYPE (lhs))) { - error ("type mismatch in binary expression"); - debug_generic_stmt (lhs_type); - debug_generic_stmt (rhs1_type); - debug_generic_stmt (rhs2_type); + error ("invalid rhs for gimple memory store"); + debug_generic_stmt (lhs); + debug_generic_stmt (rhs1); return true; } - break; + return res || verify_types_in_gimple_reference (rhs1, false); - case tcc_reference: - /* All tcc_reference trees are GIMPLE_SINGLE_RHS. Verify that - no implicit type change happens here. */ - if (!useless_type_conversion_p (lhs_type, rhs1_type)) + /* tcc_constant */ + case SSA_NAME: + case INTEGER_CST: + case REAL_CST: + case FIXED_CST: + case COMPLEX_CST: + case VECTOR_CST: + case STRING_CST: + return res; + + /* tcc_declaration */ + case CONST_DECL: + return res; + case VAR_DECL: + case PARM_DECL: + if (!is_gimple_reg (lhs) + && !is_gimple_reg (rhs1) + && is_gimple_reg_type (TREE_TYPE (lhs))) { - error ("non-trivial conversion at assignment"); - debug_generic_expr (lhs_type); - debug_generic_expr (rhs1_type); + error ("invalid rhs for gimple memory store"); + debug_generic_stmt (lhs); + debug_generic_stmt (rhs1); return true; } - return verify_types_in_gimple_reference (rhs1); - - case tcc_comparison: - { - if (!is_gimple_val (rhs1) || !is_gimple_val (rhs2)) - { - error ("invalid operands in comparison expression"); - return true; - } + return res; - /* For comparisons we do not have the operations type as the - effective type the comparison is carried out in. Instead - we require that either the first operand is trivially - convertible into the second, or the other way around. - The resulting type of a comparison may be any integral type. - Because we special-case pointers to void we allow - comparisons of pointers with the same mode as well. */ - if ((!useless_type_conversion_p (rhs1_type, rhs2_type) - && !useless_type_conversion_p (rhs2_type, rhs1_type) - && (!POINTER_TYPE_P (rhs1_type) - || !POINTER_TYPE_P (rhs2_type) - || TYPE_MODE (rhs1_type) != TYPE_MODE (rhs2_type))) - || !INTEGRAL_TYPE_P (lhs_type)) - { - error ("type mismatch in comparison expression"); - debug_generic_expr (lhs_type); - debug_generic_expr (rhs1_type); - debug_generic_expr (rhs2_type); - return true; - } - break; - } + case COND_EXPR: + case CONSTRUCTOR: + case OBJ_TYPE_REF: + case ASSERT_EXPR: + case WITH_SIZE_EXPR: + case EXC_PTR_EXPR: + case FILTER_EXPR: + case POLYNOMIAL_CHREC: + case DOT_PROD_EXPR: + case VEC_COND_EXPR: + case REALIGN_LOAD_EXPR: + /* FIXME. */ + return res; default:; } - return false; + return res; } +/* Verify the contents of a GIMPLE_ASSIGN STMT. Returns true when there + is a problem, otherwise false. */ + +static bool +verify_gimple_assign (gimple stmt) +{ + switch (gimple_assign_rhs_class (stmt)) + { + case GIMPLE_SINGLE_RHS: + return verify_gimple_assign_single (stmt); + + case GIMPLE_UNARY_RHS: + return verify_gimple_assign_unary (stmt); + + case GIMPLE_BINARY_RHS: + return verify_gimple_assign_binary (stmt); + + default: + gcc_unreachable (); + } +} /* Verify the contents of a GIMPLE_RETURN STMT. Returns true when there is a problem, otherwise false. */ static bool -verify_types_in_gimple_return (gimple stmt) +verify_gimple_return (gimple stmt) { tree op = gimple_return_retval (stmt); + tree restype = TREE_TYPE (TREE_TYPE (cfun->decl)); + /* We cannot test for present return values as we do not fix up missing + return values from the original source. */ if (op == NULL) return false; - - return verify_types_in_gimple_op (op); + + if (!is_gimple_val (op) + && TREE_CODE (op) != RESULT_DECL) + { + error ("invalid operand in return statement"); + debug_generic_stmt (op); + 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))))) + { + error ("invalid conversion in return statement"); + debug_generic_stmt (restype); + debug_generic_stmt (TREE_TYPE (op)); + return true; + } + + return false; } +/* Verify the contents of a GIMPLE_GOTO STMT. Returns true when there + is a problem, otherwise false. */ + +static bool +verify_gimple_goto (gimple stmt) +{ + tree dest = gimple_goto_dest (stmt); + + /* ??? We have two canonical forms of direct goto destinations, a + bare LABEL_DECL and an ADDR_EXPR of a LABEL_DECL. */ + if (TREE_CODE (dest) != LABEL_DECL + && (!is_gimple_val (dest) + || !POINTER_TYPE_P (TREE_TYPE (dest)))) + { + error ("goto destination is neither a label nor a pointer"); + return true; + } + + return false; +} + /* Verify the contents of a GIMPLE_SWITCH STMT. Returns true when there is a problem, otherwise false. */ static bool -verify_types_in_gimple_switch (gimple stmt) +verify_gimple_switch (gimple stmt) { if (!is_gimple_val (gimple_switch_index (stmt))) { error ("invalid operand to switch statement"); - debug_generic_expr (gimple_switch_index (stmt)); + debug_generic_stmt (gimple_switch_index (stmt)); return true; } @@ -3658,16 +4067,37 @@ verify_types_in_gimple_switch (gimple stmt) and false otherwise. */ static bool -verify_types_in_gimple_phi (gimple stmt) +verify_gimple_phi (gimple stmt) { - size_t i; + tree type = TREE_TYPE (gimple_phi_result (stmt)); + unsigned i; - if (verify_types_in_gimple_op (gimple_phi_result (stmt))) - return true; + if (!is_gimple_variable (gimple_phi_result (stmt))) + { + error ("Invalid PHI result"); + return true; + } for (i = 0; i < gimple_phi_num_args (stmt); i++) - if (verify_types_in_gimple_op (gimple_phi_arg_def (stmt, i))) - return true; + { + tree arg = gimple_phi_arg_def (stmt, i); + if ((is_gimple_reg (gimple_phi_result (stmt)) + && !is_gimple_val (arg)) + || (!is_gimple_reg (gimple_phi_result (stmt)) + && !is_gimple_addressable (arg))) + { + 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); + debug_generic_stmt (type); + debug_generic_stmt (TREE_TYPE (arg)); + return true; + } + } return false; } @@ -3693,38 +4123,39 @@ verify_types_in_gimple_stmt (gimple stmt) switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: - return verify_types_in_gimple_assign (stmt); + return verify_gimple_assign (stmt); case GIMPLE_LABEL: return TREE_CODE (gimple_label_label (stmt)) != LABEL_DECL; case GIMPLE_CALL: - return verify_types_in_gimple_call (stmt); + return verify_gimple_call (stmt); case GIMPLE_COND: - return verify_types_in_gimple_cond (stmt); + return verify_gimple_comparison (boolean_type_node, + gimple_cond_lhs (stmt), + gimple_cond_rhs (stmt)); case GIMPLE_GOTO: - return verify_types_in_gimple_op (gimple_goto_dest (stmt)); - - case GIMPLE_NOP: - case GIMPLE_PREDICT: - return false; + return verify_gimple_goto (stmt); case GIMPLE_SWITCH: - return verify_types_in_gimple_switch (stmt); + return verify_gimple_switch (stmt); case GIMPLE_RETURN: - return verify_types_in_gimple_return (stmt); + return verify_gimple_return (stmt); case GIMPLE_ASM: return false; - case GIMPLE_CHANGE_DYNAMIC_TYPE: - return verify_types_in_gimple_op (gimple_cdt_location (stmt)); - case GIMPLE_PHI: - return verify_types_in_gimple_phi (stmt); + return verify_gimple_phi (stmt); + + /* Tuples that do not have tree operands. */ + case GIMPLE_NOP: + case GIMPLE_RESX: + case GIMPLE_PREDICT: + return false; default: gcc_unreachable (); @@ -3745,44 +4176,22 @@ verify_types_in_gimple_seq_2 (gimple_seq stmts) switch (gimple_code (stmt)) { - case GIMPLE_BIND: - err |= verify_types_in_gimple_seq_2 (gimple_bind_body (stmt)); - break; - - case GIMPLE_TRY: - err |= verify_types_in_gimple_seq_2 (gimple_try_eval (stmt)); - err |= verify_types_in_gimple_seq_2 (gimple_try_cleanup (stmt)); - break; - - case GIMPLE_EH_FILTER: - err |= verify_types_in_gimple_seq_2 - (gimple_eh_filter_failure (stmt)); - break; - - case GIMPLE_CATCH: - err |= verify_types_in_gimple_seq_2 (gimple_catch_handler (stmt)); - break; - - case GIMPLE_OMP_CRITICAL: - case GIMPLE_OMP_CONTINUE: - case GIMPLE_OMP_MASTER: - case GIMPLE_OMP_ORDERED: - case GIMPLE_OMP_SECTION: - case GIMPLE_OMP_FOR: - case GIMPLE_OMP_PARALLEL: - case GIMPLE_OMP_TASK: - case GIMPLE_OMP_SECTIONS: - case GIMPLE_OMP_SINGLE: - case GIMPLE_OMP_ATOMIC_STORE: - case GIMPLE_OMP_ATOMIC_LOAD: - break; - - /* Tuples that do not have trees. */ - case GIMPLE_NOP: - case GIMPLE_RESX: - case GIMPLE_OMP_RETURN: - case GIMPLE_PREDICT: - break; + case GIMPLE_BIND: + err |= verify_types_in_gimple_seq_2 (gimple_bind_body (stmt)); + break; + + case GIMPLE_TRY: + err |= verify_types_in_gimple_seq_2 (gimple_try_eval (stmt)); + err |= verify_types_in_gimple_seq_2 (gimple_try_cleanup (stmt)); + break; + + case GIMPLE_EH_FILTER: + err |= verify_types_in_gimple_seq_2 (gimple_eh_filter_failure (stmt)); + break; + + case GIMPLE_CATCH: + err |= verify_types_in_gimple_seq_2 (gimple_catch_handler (stmt)); + break; default: { @@ -3859,7 +4268,7 @@ verify_stmt (gimple_stmt_iterator *gsi) if (addr) { debug_generic_expr (addr); - inform (input_location, "in statement"); + inform (gimple_location (gsi_stmt (*gsi)), "in statement"); debug_gimple_stmt (stmt); return true; } @@ -3871,7 +4280,10 @@ verify_stmt (gimple_stmt_iterator *gsi) to match. */ if (lookup_stmt_eh_region (stmt) >= 0) { - 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 (!stmt_could_throw_p (stmt) && cgraph_state != CGRAPH_STATE_IPA_SSA) { error ("statement marked for throw, but doesn%'t"); goto fail; @@ -3954,7 +4366,7 @@ verify_eh_throw_stmt_node (void **slot, void *data) debug_gimple_stmt (node->stmt); eh_error_found = true; } - return 0; + return 1; } @@ -4025,6 +4437,14 @@ verify_stmts (void) err |= true; } } + +#ifdef ENABLE_TYPES_CHECKING + if (verify_gimple_phi (phi)) + { + debug_gimple_stmt (phi); + err |= true; + } +#endif } for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); ) @@ -4044,6 +4464,7 @@ verify_stmts (void) if (gimple_bb (stmt) != bb) { error ("gimple_bb (stmt) is set to a wrong basic block"); + debug_gimple_stmt (stmt); err |= true; } @@ -4061,6 +4482,14 @@ verify_stmts (void) } err |= verify_stmt (&gsi); + +#ifdef ENABLE_TYPES_CHECKING + if (verify_types_in_gimple_stmt (gsi_stmt (gsi))) + { + debug_gimple_stmt (stmt); + err |= true; + } +#endif addr = walk_gimple_op (gsi_stmt (gsi), verify_node_sharing, &wi); if (addr) { @@ -4445,7 +4874,7 @@ gimple_block_label (basic_block bb) } } - label = create_artificial_label (); + label = create_artificial_label (UNKNOWN_LOCATION); stmt = gimple_build_label (label); gsi_insert_before (&s, stmt, GSI_NEW_STMT); return label; @@ -4512,10 +4941,13 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) if (e->dest == dest) return NULL; + if (e->flags & EDGE_EH) + return redirect_eh_edge (e, dest); + gsi = gsi_last_bb (bb); stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi); - switch (stmt ? gimple_code (stmt) : ERROR_MARK) + switch (stmt ? gimple_code (stmt) : GIMPLE_ERROR_MARK) { case GIMPLE_COND: /* For COND_EXPR, we only need to redirect the edge. */ @@ -4604,7 +5036,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest) static bool gimple_can_remove_branch_p (const_edge e) { - if (e->flags & EDGE_ABNORMAL) + if (e->flags & (EDGE_ABNORMAL | EDGE_EH)) return false; return true; @@ -4742,7 +5174,6 @@ gimple_duplicate_bb (basic_block bb) operands. */ copy = gimple_copy (stmt); gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT); - copy_virtual_operands (copy, stmt); region = lookup_stmt_eh_region (stmt); if (region >= 0) add_stmt_to_eh_region (copy, region); @@ -4914,7 +5345,7 @@ gimple_duplicate_sese_region (edge entry, edge exit, free_region_copy = true; } - gcc_assert (!need_ssa_update_p ()); + gcc_assert (!need_ssa_update_p (cfun)); /* Record blocks outside the region that are dominated by something inside. */ @@ -5073,7 +5504,7 @@ gimple_duplicate_sese_tail (edge entry ATTRIBUTE_UNUSED, edge exit ATTRIBUTE_UNU free_region_copy = true; } - gcc_assert (!need_ssa_update_p ()); + gcc_assert (!need_ssa_update_p (cfun)); /* Record blocks outside the region that are dominated by something inside. */ @@ -5400,19 +5831,6 @@ mark_virtual_ops_in_bb (basic_block bb) mark_virtual_ops_for_renaming (gsi_stmt (gsi)); } -/* Marks virtual operands of all statements in basic blocks BBS for - renaming. */ - -static void -mark_virtual_ops_in_region (VEC (basic_block,heap) *bbs) -{ - basic_block bb; - unsigned i; - - for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++) - mark_virtual_ops_in_bb (bb); -} - /* 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 @@ -5519,7 +5937,7 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, old_len = VEC_length (basic_block, cfg->x_label_to_block_map); if (old_len <= (unsigned) uid) { - new_len = 3 * uid / 2; + new_len = 3 * uid / 2 + 1; VEC_safe_grow_cleared (basic_block, gc, cfg->x_label_to_block_map, new_len); } @@ -5551,6 +5969,23 @@ move_block_to_fn (struct function *dest_cfun, basic_block bb, update_stmt (stmt); pop_cfun (); } + + FOR_EACH_EDGE (e, ei, bb->succs) + if (e->goto_locus) + { + tree block = e->goto_block; + if (d->orig_block == NULL_TREE + || block == d->orig_block) + e->goto_block = d->new_block; +#ifdef ENABLE_CHECKING + else if (block != d->new_block) + { + while (block && block != d->orig_block) + block = BLOCK_SUPERCONTEXT (block); + gcc_assert (block); + } +#endif + } } /* Examine the statements in BB (which is in SRC_CFUN); find and return @@ -5598,7 +6033,7 @@ new_label_mapper (tree decl, void *data) m = XNEW (struct tree_map); m->hash = DECL_UID (decl); m->base.from = decl; - m->to = create_artificial_label (); + m->to = create_artificial_label (UNKNOWN_LOCATION); LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl); if (LABEL_DECL_UID (m->to) >= cfun->cfg->last_label_uid) cfun->cfg->last_label_uid = LABEL_DECL_UID (m->to) + 1; @@ -5623,6 +6058,8 @@ replace_block_vars_by_duplicates (tree block, struct pointer_map_t *vars_map, for (tp = &BLOCK_VARS (block); *tp; tp = &TREE_CHAIN (*tp)) { t = *tp; + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != CONST_DECL) + continue; replace_by_duplicate_decl (&t, vars_map, to_context); if (t != *tp) { @@ -5762,11 +6199,6 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb, pop_cfun (); - /* The ssa form for virtual operands in the source function will have to - be repaired. We do not care for the real operands -- the sese region - must be closed with respect to those. */ - mark_virtual_ops_in_region (bbs); - /* Move blocks from BBS into DEST_CFUN. */ gcc_assert (VEC_length (basic_block, bbs) >= 2); after = dest_cfun->cfg->x_entry_block_ptr; @@ -5898,7 +6330,7 @@ dump_function_to_file (tree fn, FILE *file, int flags) if (dsf && (flags & TDF_DETAILS)) dump_eh_tree (file, dsf); - if (flags & TDF_RAW && !gimple_body (fn)) + if (flags & TDF_RAW && !gimple_has_body_p (fn)) { dump_node (fn, TDF_SLIM | flags, file); return; @@ -6220,15 +6652,20 @@ need_fake_edge_p (gimple t) && fndecl && DECL_BUILT_IN (fndecl) && (call_flags & ECF_NOTHROW) - && !(call_flags & ECF_NORETURN) - && !(call_flags & ECF_RETURNS_TWICE)) - return false; + && !(call_flags & ECF_RETURNS_TWICE) + /* fork() doesn't really return twice, but the effect of + wrapping it in __gcov_fork() which calls __gcov_flush() + and clears the counters before forking has the same + effect as returning twice. Force a fake edge. */ + && !(DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FORK)) + return false; if (is_gimple_call (t) && !(call_flags & ECF_NORETURN)) return true; - if (gimple_code (t) == ASM_EXPR + if (gimple_code (t) == GIMPLE_ASM && (gimple_asm_volatile_p (t) || gimple_asm_input_p (t))) return true; @@ -6388,20 +6825,6 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb) return changed; } -/* Stores all basic blocks dominated by BB to DOM_BBS. */ - -static void -get_all_dominated_blocks (basic_block bb, VEC (basic_block, heap) **dom_bbs) -{ - basic_block son; - - VEC_safe_push (basic_block, heap, *dom_bbs, bb); - for (son = first_dom_son (CDI_DOMINATORS, bb); - son; - son = next_dom_son (CDI_DOMINATORS, son)) - get_all_dominated_blocks (son, dom_bbs); -} - /* 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.*/ @@ -6461,7 +6884,7 @@ remove_edge_and_dominated_blocks (edge e) get_immediate_dominator (CDI_DOMINATORS, e->dest)->index); else { - get_all_dominated_blocks (e->dest, &bbs_to_remove); + 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_EDGE (f, ei, bb->succs) @@ -6713,10 +7136,31 @@ split_critical_edges (void) FOR_ALL_BB (bb) { FOR_EACH_EDGE (e, ei, bb->succs) - if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL)) - { + { + if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL)) split_edge (e); - } + /* PRE inserts statements to edges and expects that + since split_critical_edges was done beforehand, committing edge + insertions will not split more edges. In addition to critical + edges we must split edges that have multiple successors and + end by control flow statements, such as RESX. + Go ahead and split them too. This matches the logic in + gimple_find_edge_insert_loc. */ + else if ((!single_pred_p (e->dest) + || phi_nodes (e->dest) + || e->dest == EXIT_BLOCK_PTR) + && e->src != ENTRY_BLOCK_PTR + && !(e->flags & EDGE_ABNORMAL)) + { + gimple_stmt_iterator gsi; + + 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) + split_edge (e); + } + } } end_recording_case_labels (); return 0; @@ -6737,7 +7181,7 @@ struct gimple_opt_pass pass_split_crit_edges = PROP_no_crit_edges, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + TODO_dump_func | TODO_verify_flow /* todo_flags_finish */ } }; @@ -6880,7 +7324,7 @@ struct gimple_opt_pass pass_warn_function_return = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ PROP_cfg, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */ @@ -6914,7 +7358,7 @@ struct gimple_opt_pass pass_warn_function_noreturn = NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - 0, /* tv_id */ + TV_NONE, /* tv_id */ PROP_cfg, /* properties_required */ 0, /* properties_provided */ 0, /* properties_destroyed */