diff options
Diffstat (limited to 'gcc/tree-cfg.cc')
-rw-r--r-- | gcc/tree-cfg.cc | 331 |
1 files changed, 118 insertions, 213 deletions
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 6a95b82..3d23f17 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -114,43 +114,6 @@ struct replace_decls_d tree to_context; }; -/* Hash table to store last discriminator assigned for each locus. */ -struct locus_discrim_map -{ - int location_line; - int discriminator; -}; - -/* Hashtable helpers. */ - -struct locus_discrim_hasher : free_ptr_hash <locus_discrim_map> -{ - static inline hashval_t hash (const locus_discrim_map *); - static inline bool equal (const locus_discrim_map *, - const locus_discrim_map *); -}; - -/* Trivial hash function for a location_t. ITEM is a pointer to - a hash table entry that maps a location_t to a discriminator. */ - -inline hashval_t -locus_discrim_hasher::hash (const locus_discrim_map *item) -{ - return item->location_line; -} - -/* Equality function for the locus-to-discriminator map. A and B - point to the two hash table entries to compare. */ - -inline bool -locus_discrim_hasher::equal (const locus_discrim_map *a, - const locus_discrim_map *b) -{ - return a->location_line == b->location_line; -} - -static hash_table<locus_discrim_hasher> *discriminator_per_locus; - /* Basic blocks and flowgraphs. */ static void make_blocks (gimple_seq); @@ -168,7 +131,6 @@ static edge gimple_try_redirect_by_replacing_jump (edge, basic_block); static inline bool stmt_starts_bb_p (gimple *, gimple *); static bool gimple_verify_flow_info (void); static void gimple_make_forwarder_block (edge); -static gimple *first_non_label_nondebug_stmt (basic_block); static bool verify_gimple_transaction (gtransaction *); static bool call_can_make_abnormal_goto (gimple *); @@ -247,12 +209,9 @@ build_gimple_cfg (gimple_seq seq) group_case_labels (); /* Create the edges of the flowgraph. */ - discriminator_per_locus = new hash_table<locus_discrim_hasher> (13); make_edges (); assign_discriminators (); cleanup_dead_labels (); - delete discriminator_per_locus; - discriminator_per_locus = NULL; } /* Look for ANNOTATE calls with loop annotation kind in BB; if found, remove @@ -1120,77 +1079,41 @@ gimple_find_sub_bbs (gimple_seq seq, gimple_stmt_iterator *gsi) return true; } -/* 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 (int line) -{ - struct locus_discrim_map item; - struct locus_discrim_map **slot; - - item.location_line = line; - item.discriminator = 0; - slot = discriminator_per_locus->find_slot_with_hash (&item, line, INSERT); - gcc_assert (slot); - if (*slot == HTAB_EMPTY_ENTRY) - { - *slot = XNEW (struct locus_discrim_map); - gcc_assert (*slot); - (*slot)->location_line = line; - (*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, expanded_location *from, location_t locus2) +/* Auto-profile needs discriminator to distinguish statements with same line + number (file name is ignored) which are in different basic block. This + map keeps track of current discriminator for a given line number. */ +struct discrim_entry { - expanded_location to; - - if (locus1 == locus2) - return true; - - 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 - && filename_cmp (from->file, to.file) == 0); -} + /* ID of basic block we saw line number last time. */ + unsigned int bb_id; + /* Discriminator we used. */ + unsigned int discrim; +}; -/* Assign a unique discriminator value to all statements in block bb that - have the same line number as locus. */ +/* Return updated LOC with discriminator for use in basic block BB_ID. + MAP keeps track of current values. */ -static void -assign_discriminator (location_t locus, basic_block bb) +location_t +assign_discriminator (location_t loc, unsigned int bb_id, + hash_map<int_hash <int64_t, -1, -2>, discrim_entry> &map) { - gimple_stmt_iterator gsi; - int discriminator; - - if (locus == UNKNOWN_LOCATION) - return; - - expanded_location locus_e = expand_location (locus); - - discriminator = next_discriminator_for_locus (locus_e.line); - - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + bool existed; + discrim_entry &e = map.get_or_insert (LOCATION_LINE (loc), &existed); + gcc_checking_assert (!has_discriminator (loc)); + if (!existed) { - gimple *stmt = gsi_stmt (gsi); - location_t stmt_locus = gimple_location (stmt); - if (same_line_p (locus, &locus_e, stmt_locus)) - gimple_set_location (stmt, - location_with_discriminator (stmt_locus, discriminator)); + e.bb_id = bb_id; + e.discrim = 0; + return loc; } + if (e.bb_id != bb_id) + { + e.bb_id = bb_id; + e.discrim++; + } + if (e.discrim) + return location_with_discriminator (loc, e.discrim); + return loc; } /* Assign discriminators to statement locations. */ @@ -1198,92 +1121,54 @@ assign_discriminator (location_t locus, basic_block bb) static void assign_discriminators (void) { + hash_map<int_hash <int64_t, -1, -2>, discrim_entry> map (13); + unsigned int bb_id = 0; basic_block bb; - FOR_EACH_BB_FN (bb, cfun) { - edge e; - edge_iterator ei; - gimple_stmt_iterator gsi; - location_t curr_locus = UNKNOWN_LOCATION; - expanded_location curr_locus_e = {}; - int curr_discr = 0; - + location_t prev_loc = UNKNOWN_LOCATION, prev_replacement = UNKNOWN_LOCATION; /* Traverse the basic block, if two function calls within a basic block are mapped to the same line, assign a new discriminator because a call stmt could be a split point of a basic block. */ - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); + !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - - /* Don't allow debug stmts to affect discriminators, but - allow them to take discriminators when they're on the - same line as the preceding nondebug stmt. */ - if (is_gimple_debug (stmt)) - { - if (curr_locus != UNKNOWN_LOCATION - && same_line_p (curr_locus, &curr_locus_e, - gimple_location (stmt))) - { - location_t loc = gimple_location (stmt); - location_t dloc = location_with_discriminator (loc, - curr_discr); - gimple_set_location (stmt, dloc); - } - continue; - } - if (curr_locus == UNKNOWN_LOCATION) - { - curr_locus = gimple_location (stmt); - curr_locus_e = expand_location (curr_locus); - } - else if (!same_line_p (curr_locus, &curr_locus_e, gimple_location (stmt))) - { - curr_locus = gimple_location (stmt); - curr_locus_e = expand_location (curr_locus); - curr_discr = 0; - } - else if (curr_discr != 0) + location_t loc = gimple_location (stmt); + if (loc == UNKNOWN_LOCATION) + continue; + if (loc == prev_loc) + gimple_set_location (stmt, prev_replacement); + else { - location_t loc = gimple_location (stmt); - location_t dloc = location_with_discriminator (loc, curr_discr); - gimple_set_location (stmt, dloc); + prev_loc = loc; + prev_replacement = assign_discriminator (loc, bb_id, map); + gimple_set_location (stmt, prev_replacement); } - /* Allocate a new discriminator for CALL stmt. */ + /* Break basic blocks after each call. This is requires so each + call site has unque discriminator. + More correctly, we can break after each statement that can possibly + terinate execution of the basic block, but for auto-profile this + precision is probably not useful. */ if (gimple_code (stmt) == GIMPLE_CALL) - curr_discr = next_discriminator_for_locus (curr_locus_e.line); - } - - gimple *last = last_nondebug_stmt (bb); - location_t locus = last ? gimple_location (last) : UNKNOWN_LOCATION; - if (locus == UNKNOWN_LOCATION) - continue; - - expanded_location locus_e = expand_location (locus); - - FOR_EACH_EDGE (e, ei, bb->succs) - { - gimple *first = first_non_label_nondebug_stmt (e->dest); - gimple *last = last_nondebug_stmt (e->dest); - - gimple *stmt_on_same_line = NULL; - if (first && same_line_p (locus, &locus_e, - gimple_location (first))) - stmt_on_same_line = first; - else if (last && same_line_p (locus, &locus_e, - gimple_location (last))) - stmt_on_same_line = last; - - if (stmt_on_same_line) { - if (has_discriminator (gimple_location (stmt_on_same_line)) - && !has_discriminator (locus)) - assign_discriminator (locus, bb); - else - assign_discriminator (locus, e->dest); + prev_loc = UNKNOWN_LOCATION; + bb_id++; } } + /* IF basic block has multiple sucessors, consdier every edge as a separate + block. */ + if (!single_succ_p (bb)) + bb_id++; + for (edge e : bb->succs) + if (e->goto_locus != UNKNOWN_LOCATION) + { + e->goto_locus = assign_discriminator (e->goto_locus, bb_id, map); + bb_id++; + } + bb_id++; } + } /* Create the edges for a GIMPLE_COND starting at block BB. */ @@ -2948,16 +2833,6 @@ first_stmt (basic_block bb) return stmt; } -/* Return the first non-label/non-debug statement in basic block BB. */ - -static gimple * -first_non_label_nondebug_stmt (basic_block bb) -{ - gimple_stmt_iterator i; - i = gsi_start_nondebug_after_labels_bb (bb); - return !gsi_end_p (i) ? gsi_stmt (i) : NULL; -} - /* Return the last statement in basic block BB. */ gimple * @@ -3867,22 +3742,6 @@ verify_gimple_assign_unary (gassign *stmt) return false; - case NEGATE_EXPR: - case ABS_EXPR: - case BIT_NOT_EXPR: - case PAREN_EXPR: - case CONJ_EXPR: - /* Disallow pointer and offset types for many of the unary gimple. */ - if (POINTER_TYPE_P (lhs_type) - || TREE_CODE (lhs_type) == OFFSET_TYPE) - { - error ("invalid types for %qs", code_name); - debug_generic_expr (lhs_type); - debug_generic_expr (rhs1_type); - return true; - } - break; - case ABSU_EXPR: if (!ANY_INTEGRAL_TYPE_P (lhs_type) || !TYPE_UNSIGNED (lhs_type) @@ -3908,6 +3767,27 @@ verify_gimple_assign_unary (gassign *stmt) } return false; + case CONJ_EXPR: + if (TREE_CODE (lhs_type) != COMPLEX_TYPE) + { +diagnose_unary_lhs: + error ("invalid type for %qs", code_name); + debug_generic_expr (lhs_type); + return true; + } + break; + + case NEGATE_EXPR: + case ABS_EXPR: + case BIT_NOT_EXPR: + if (POINTER_TYPE_P (lhs_type) || TREE_CODE (lhs_type) == OFFSET_TYPE) + goto diagnose_unary_lhs; + /* FALLTHRU */ + case PAREN_EXPR: + if (AGGREGATE_TYPE_P (lhs_type)) + goto diagnose_unary_lhs; + break; + default: gcc_unreachable (); } @@ -4618,6 +4498,14 @@ verify_gimple_assign_single (gassign *stmt) return true; } + /* LHS can't be a constant or an address expression. */ + if (CONSTANT_CLASS_P (lhs)|| TREE_CODE (lhs) == ADDR_EXPR) + { + error ("invalid LHS (%qs) for assignment: %qs", + get_tree_code_name (TREE_CODE (lhs)), code_name); + return true; + } + if (gimple_clobber_p (stmt) && !(DECL_P (lhs) || TREE_CODE (lhs) == MEM_REF)) { @@ -4740,6 +4628,11 @@ verify_gimple_assign_single (gassign *stmt) if (CONSTRUCTOR_NELTS (rhs1) == 0) return res; + if (!is_gimple_reg (lhs)) + { + error ("non-register as LHS with vector constructor"); + return true; + } /* For vector CONSTRUCTORs we require that either it is empty CONSTRUCTOR, or it is a CONSTRUCTOR of smaller vector elements (then the element count must be correct to cover the whole @@ -5752,6 +5645,12 @@ gimple_verify_flow_info (void) error ("probability of edge from entry block not initialized"); err = true; } + if (!EXIT_BLOCK_PTR_FOR_FN (cfun) + ->count.compatible_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count)) + { + error ("exit block count is not compatible with entry block count"); + err = true; + } FOR_EACH_BB_FN (bb, cfun) @@ -5775,6 +5674,12 @@ gimple_verify_flow_info (void) err = true; } } + if (!bb->count.compatible_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count)) + { + error ("count of bb %d is not compatible with entry block count", + bb->index); + err = true; + } /* Skip labels on the start of basic block. */ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) @@ -8322,7 +8227,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) fprintf (file, ", "); tree name = get_attribute_name (chain); - print_generic_expr (file, name, dump_flags); + print_generic_expr (file, name, flags); if (TREE_VALUE (chain) != NULL_TREE) { fprintf (file, " ("); @@ -8333,13 +8238,13 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) "omp declare variant base")) { tree a = TREE_VALUE (chain); - print_generic_expr (file, TREE_PURPOSE (a), dump_flags); + print_generic_expr (file, TREE_PURPOSE (a), flags); fprintf (file, " match "); print_omp_context_selector (file, TREE_VALUE (a), - dump_flags); + flags); } else - print_generic_expr (file, TREE_VALUE (chain), dump_flags); + print_generic_expr (file, TREE_VALUE (chain), flags); fprintf (file, ")"); } } @@ -8361,7 +8266,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) } print_generic_expr (file, TREE_TYPE (TREE_TYPE (fndecl)), - dump_flags | TDF_SLIM); + flags | TDF_SLIM); fprintf (file, " __GIMPLE (%s", (fun->curr_properties & PROP_ssa) ? "ssa" : (fun->curr_properties & PROP_cfg) ? "cfg" @@ -8374,7 +8279,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) fprintf (file, ",%s(%" PRIu64 ")", profile_quality_as_string (bb->count.quality ()), bb->count.value ()); - if (dump_flags & TDF_UID) + if (flags & TDF_UID) fprintf (file, ")\n%sD_%u (", function_name (fun), DECL_UID (fndecl)); else @@ -8383,8 +8288,8 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) } else { - print_generic_expr (file, TREE_TYPE (fntype), dump_flags); - if (dump_flags & TDF_UID) + print_generic_expr (file, TREE_TYPE (fntype), flags); + if (flags & TDF_UID) fprintf (file, " %sD.%u %s(", function_name (fun), DECL_UID (fndecl), tmclone ? "[tm-clone] " : ""); else @@ -8395,9 +8300,9 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) arg = DECL_ARGUMENTS (fndecl); while (arg) { - print_generic_expr (file, TREE_TYPE (arg), dump_flags); + print_generic_expr (file, TREE_TYPE (arg), flags); fprintf (file, " "); - print_generic_expr (file, arg, dump_flags); + print_generic_expr (file, arg, flags); if (DECL_CHAIN (arg)) fprintf (file, ", "); arg = DECL_CHAIN (arg); |