struct cgraph_node * cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, bool update_original, vec<cgraph_edge_p> redirect_callers, bool call_duplication_hook, struct cgraph_node *new_inlined_to) { struct cgraph_node *new_node = cgraph_create_empty_node (); struct cgraph_edge *e; gcov_type count_scale; unsigned i; new_node->decl = decl; symtab_register_node (new_node); new_node->origin = n->origin; new_node->lto_file_data = n->lto_file_data; if (new_node->origin) { new_node->next_nested = new_node->origin->nested; new_node->origin->nested = new_node; } new_node->analyzed = n->analyzed; new_node->definition = n->definition; new_node->local = n->local; new_node->externally_visible = false; new_node->local.local = true; new_node->global = n->global; new_node->global.inlined_to = new_inlined_to; new_node->rtl = n->rtl; new_node->count = count; new_node->frequency = n->frequency; new_node->clone = n->clone; new_node->clone.tree_map = NULL; new_node->tp_first_run = n->tp_first_run; if (n->count) { if (new_node->count > n->count) count_scale = REG_BR_PROB_BASE; else count_scale = GCOV_COMPUTE_SCALE (new_node->count, n->count); } else count_scale = 0; if (update_original) { n->count -= count; if (n->count < 0) n->count = 0; } FOR_EACH_VEC_ELT (redirect_callers, i, e) { /* Redirect calls to the old version node to point to its new version. */ cgraph_redirect_edge_callee (e, new_node); }
unsigned int execute_fixup_cfg (void) { basic_block bb; gimple_stmt_iterator gsi; int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0; gcov_type count_scale; edge e; edge_iterator ei; count_scale = GCOV_COMPUTE_SCALE (cgraph_get_node (current_function_decl)->count, ENTRY_BLOCK_PTR->count); ENTRY_BLOCK_PTR->count = cgraph_get_node (current_function_decl)->count; EXIT_BLOCK_PTR->count = apply_scale (EXIT_BLOCK_PTR->count, count_scale); FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) e->count = apply_scale (e->count, count_scale); FOR_EACH_BB (bb) { bb->count = apply_scale (bb->count, count_scale); for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); tree decl = is_gimple_call (stmt) ? gimple_call_fndecl (stmt) : NULL; if (decl) { int flags = gimple_call_flags (stmt); if (flags & (ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE)) { if (gimple_purge_dead_abnormal_call_edges (bb)) todo |= TODO_cleanup_cfg; if (gimple_in_ssa_p (cfun)) { todo |= TODO_update_ssa | TODO_cleanup_cfg; update_stmt (stmt); } } if (flags & ECF_NORETURN && fixup_noreturn_call (stmt)) todo |= TODO_cleanup_cfg; } if (maybe_clean_eh_stmt (stmt) && gimple_purge_dead_eh_edges (bb)) todo |= TODO_cleanup_cfg; } FOR_EACH_EDGE (e, ei, bb->succs) e->count = apply_scale (e->count, count_scale); /* If we have a basic block with no successors that does not end with a control statement or a noreturn call end it with a call to __builtin_unreachable. This situation can occur when inlining a noreturn call that does in fact return. */ if (EDGE_COUNT (bb->succs) == 0) { gimple stmt = last_stmt (bb); if (!stmt || (!is_ctrl_stmt (stmt) && (!is_gimple_call (stmt) || (gimple_call_flags (stmt) & ECF_NORETURN) == 0))) { stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0); gimple_stmt_iterator gsi = gsi_last_bb (bb); gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); } } } if (count_scale != REG_BR_PROB_BASE) compute_function_frequency (); /* We just processed all calls. */ if (cfun->gimple_df) vec_free (MODIFIED_NORETURN_CALLS (cfun)); /* Dump a textual representation of the flowgraph. */ if (dump_file) gimple_dump_cfg (dump_file, dump_flags); if (current_loops && (todo & TODO_cleanup_cfg)) loops_state_set (LOOPS_NEED_FIXUP); return todo; }
void do_jump_1 (enum tree_code code, tree op0, tree op1, rtx if_false_label, rtx if_true_label, int prob) { enum machine_mode mode; rtx drop_through_label = 0; switch (code) { case EQ_EXPR: { tree inner_type = TREE_TYPE (op0); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_FLOAT); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_INT); if (integer_zerop (op1)) do_jump (op0, if_true_label, if_false_label, inv (prob)); else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT && !can_compare_p (EQ, TYPE_MODE (inner_type), ccp_jump)) do_jump_by_parts_equality (op0, op1, if_false_label, if_true_label, prob); else do_compare_and_jump (op0, op1, EQ, EQ, if_false_label, if_true_label, prob); break; } case NE_EXPR: { tree inner_type = TREE_TYPE (op0); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_FLOAT); gcc_assert (GET_MODE_CLASS (TYPE_MODE (inner_type)) != MODE_COMPLEX_INT); if (integer_zerop (op1)) do_jump (op0, if_false_label, if_true_label, prob); else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT && !can_compare_p (NE, TYPE_MODE (inner_type), ccp_jump)) do_jump_by_parts_equality (op0, op1, if_true_label, if_false_label, inv (prob)); else do_compare_and_jump (op0, op1, NE, NE, if_false_label, if_true_label, prob); break; } case LT_EXPR: mode = TYPE_MODE (TREE_TYPE (op0)); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (LT, mode, ccp_jump)) do_jump_by_parts_greater (op0, op1, 1, if_false_label, if_true_label, prob); else do_compare_and_jump (op0, op1, LT, LTU, if_false_label, if_true_label, prob); break; case LE_EXPR: mode = TYPE_MODE (TREE_TYPE (op0)); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (LE, mode, ccp_jump)) do_jump_by_parts_greater (op0, op1, 0, if_true_label, if_false_label, inv (prob)); else do_compare_and_jump (op0, op1, LE, LEU, if_false_label, if_true_label, prob); break; case GT_EXPR: mode = TYPE_MODE (TREE_TYPE (op0)); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (GT, mode, ccp_jump)) do_jump_by_parts_greater (op0, op1, 0, if_false_label, if_true_label, prob); else do_compare_and_jump (op0, op1, GT, GTU, if_false_label, if_true_label, prob); break; case GE_EXPR: mode = TYPE_MODE (TREE_TYPE (op0)); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (GE, mode, ccp_jump)) do_jump_by_parts_greater (op0, op1, 1, if_true_label, if_false_label, inv (prob)); else do_compare_and_jump (op0, op1, GE, GEU, if_false_label, if_true_label, prob); break; case ORDERED_EXPR: do_compare_and_jump (op0, op1, ORDERED, ORDERED, if_false_label, if_true_label, prob); break; case UNORDERED_EXPR: do_compare_and_jump (op0, op1, UNORDERED, UNORDERED, if_false_label, if_true_label, prob); break; case UNLT_EXPR: do_compare_and_jump (op0, op1, UNLT, UNLT, if_false_label, if_true_label, prob); break; case UNLE_EXPR: do_compare_and_jump (op0, op1, UNLE, UNLE, if_false_label, if_true_label, prob); break; case UNGT_EXPR: do_compare_and_jump (op0, op1, UNGT, UNGT, if_false_label, if_true_label, prob); break; case UNGE_EXPR: do_compare_and_jump (op0, op1, UNGE, UNGE, if_false_label, if_true_label, prob); break; case UNEQ_EXPR: do_compare_and_jump (op0, op1, UNEQ, UNEQ, if_false_label, if_true_label, prob); break; case LTGT_EXPR: do_compare_and_jump (op0, op1, LTGT, LTGT, if_false_label, if_true_label, prob); break; case TRUTH_ANDIF_EXPR: { /* Spread the probability that the expression is false evenly between the two conditions. So the first condition is false half the total probability of being false. The second condition is false the other half of the total probability of being false, so its jump has a false probability of half the total, relative to the probability we reached it (i.e. the first condition was true). */ int op0_prob = -1; int op1_prob = -1; if (prob != -1) { int false_prob = inv (prob); int op0_false_prob = false_prob / 2; int op1_false_prob = GCOV_COMPUTE_SCALE ((false_prob / 2), inv (op0_false_prob)); /* Get the probability that each jump below is true. */ op0_prob = inv (op0_false_prob); op1_prob = inv (op1_false_prob); } if (if_false_label == NULL_RTX) { drop_through_label = gen_label_rtx (); do_jump (op0, drop_through_label, NULL_RTX, op0_prob); do_jump (op1, NULL_RTX, if_true_label, op1_prob); } else { do_jump (op0, if_false_label, NULL_RTX, op0_prob); do_jump (op1, if_false_label, if_true_label, op1_prob); } break; } case TRUTH_ORIF_EXPR: { /* Spread the probability evenly between the two conditions. So the first condition has half the total probability of being true. The second condition has the other half of the total probability, so its jump has a probability of half the total, relative to the probability we reached it (i.e. the first condition was false). */ int op0_prob = -1; int op1_prob = -1; if (prob != -1) { op0_prob = prob / 2; op1_prob = GCOV_COMPUTE_SCALE ((prob / 2), inv (op0_prob)); } if (if_true_label == NULL_RTX) { drop_through_label = gen_label_rtx (); do_jump (op0, NULL_RTX, drop_through_label, op0_prob); do_jump (op1, if_false_label, NULL_RTX, op1_prob); } else { do_jump (op0, NULL_RTX, if_true_label, op0_prob); do_jump (op1, if_false_label, if_true_label, op1_prob); } break; } default: gcc_unreachable (); } if (drop_through_label) { do_pending_stack_adjust (); emit_label (drop_through_label); } }