- tree stmt1, stmt2, stmt3, stmt4;
- tree tmp1, tmp2, tmp3;
- tree label_decl1 = create_artificial_label ();
- tree label_decl2 = create_artificial_label ();
- tree label_decl3 = create_artificial_label ();
- tree label1, label2, label3;
- tree bb1end, bb2end, bb3end;
- basic_block bb, bb2, bb3, bb4;
- tree optype = TREE_TYPE (operation);
- edge e12, e13, e23, e24, e34;
- block_stmt_iterator bsi;
- tree result = create_tmp_var (optype, "PROF");
-
- bb = bb_for_stmt (stmt);
- bsi = bsi_for_stmt (stmt);
-
- tmp1 = create_tmp_var (optype, "PROF");
- tmp2 = create_tmp_var (optype, "PROF");
- tmp3 = create_tmp_var (optype, "PROF");
- stmt1 = build2 (MODIFY_EXPR, optype, tmp1, fold_convert (optype, op2));
- stmt2 = build2 (MODIFY_EXPR, optype, tmp2,
- build2 (PLUS_EXPR, optype, op2, integer_minus_one_node));
- stmt3 = build2 (MODIFY_EXPR, optype, tmp3,
- build2 (BIT_AND_EXPR, optype, tmp2, tmp1));
- stmt4 = build3 (COND_EXPR, void_type_node,
- build2 (NE_EXPR, boolean_type_node, tmp3, integer_zero_node),
- build1 (GOTO_EXPR, void_type_node, label_decl2),
- build1 (GOTO_EXPR, void_type_node, label_decl1));
- bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
- bb1end = stmt4;
+ struct cgraph_node *n;
+
+ if (get_last_funcdef_no ())
+ VEC_safe_grow_cleared (cgraph_node_ptr, heap,
+ cgraph_node_map, get_last_funcdef_no ());
+
+ for (n = cgraph_nodes; n; n = n->next)
+ {
+ if (DECL_STRUCT_FUNCTION (n->decl))
+ VEC_replace (cgraph_node_ptr, cgraph_node_map,
+ DECL_STRUCT_FUNCTION (n->decl)->funcdef_no, n);
+ }
+}
+
+/* Delete the CGRAPH_NODE_MAP. */
+
+void
+del_node_map (void)
+{
+ VEC_free (cgraph_node_ptr, heap, cgraph_node_map);
+ cgraph_node_map = NULL;
+}
+
+/* Return cgraph node for function with pid */
+
+static inline struct cgraph_node*
+find_func_by_funcdef_no (int func_id)
+{
+ int max_id = get_last_funcdef_no ();
+ if (func_id >= max_id || VEC_index (cgraph_node_ptr,
+ cgraph_node_map,
+ func_id) == NULL)
+ {
+ if (flag_profile_correction)
+ inform (DECL_SOURCE_LOCATION (current_function_decl),
+ "Inconsistent profile: indirect call target (%d) does not exist", func_id);
+ else
+ error ("Inconsistent profile: indirect call target (%d) does not exist", func_id);
+
+ return NULL;
+ }
+
+ return VEC_index (cgraph_node_ptr, cgraph_node_map, func_id);
+}
+
+/* Perform sanity check on the indirect call target. Due to race conditions,
+ false function target may be attributed to an indirect call site. If the
+ call expression type mismatches with the target function's type, expand_call
+ may ICE. Here we only do very minimal sanity check just to make compiler happy.
+ Returns true if TARGET is considered ok for call CALL_STMT. */
+
+static bool
+check_ic_target (gimple call_stmt, struct cgraph_node *target)
+{
+ location_t locus;
+ if (gimple_check_call_matching_types (call_stmt, target->decl))
+ return true;
+
+ locus = gimple_location (call_stmt);
+ inform (locus, "Skipping target %s with mismatching types for icall ",
+ cgraph_node_name (target));
+ return false;
+}
+
+/* Do transformation
+
+ if (actual_callee_address == address_of_most_common_function/method)
+ do direct call
+ else
+ old call
+ */
+
+static gimple
+gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
+ int prob, gcov_type count, gcov_type all)
+{
+ gimple dcall_stmt, load_stmt, cond_stmt;
+ tree tmp0, tmp1, tmpv, tmp;
+ basic_block cond_bb, dcall_bb, icall_bb, join_bb = NULL;
+ tree optype = build_pointer_type (void_type_node);
+ edge e_cd, e_ci, e_di, e_dj = NULL, e_ij;
+ gimple_stmt_iterator gsi;
+ int lp_nr, dflags;
+
+ cond_bb = gimple_bb (icall_stmt);
+ gsi = gsi_for_stmt (icall_stmt);
+
+ tmpv = create_tmp_reg (optype, "PROF");
+ tmp0 = make_ssa_name (tmpv, NULL);
+ tmp1 = make_ssa_name (tmpv, NULL);
+ tmp = unshare_expr (gimple_call_fn (icall_stmt));
+ load_stmt = gimple_build_assign (tmp0, tmp);
+ SSA_NAME_DEF_STMT (tmp0) = load_stmt;
+ gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
+
+ tmp = fold_convert (optype, build_addr (direct_call->decl,
+ current_function_decl));
+ load_stmt = gimple_build_assign (tmp1, tmp);
+ SSA_NAME_DEF_STMT (tmp1) = load_stmt;
+ gsi_insert_before (&gsi, load_stmt, GSI_SAME_STMT);
+
+ cond_stmt = gimple_build_cond (EQ_EXPR, tmp1, tmp0, NULL_TREE, NULL_TREE);
+ gsi_insert_before (&gsi, cond_stmt, GSI_SAME_STMT);
+
+ gimple_set_vdef (icall_stmt, NULL_TREE);
+ gimple_set_vuse (icall_stmt, NULL_TREE);
+ update_stmt (icall_stmt);
+ dcall_stmt = gimple_copy (icall_stmt);
+ gimple_call_set_fndecl (dcall_stmt, direct_call->decl);
+ dflags = flags_from_decl_or_type (direct_call->decl);
+ if ((dflags & ECF_NORETURN) != 0)
+ gimple_call_set_lhs (dcall_stmt, NULL_TREE);
+ gsi_insert_before (&gsi, dcall_stmt, GSI_SAME_STMT);
+
+ /* Fix CFG. */
+ /* Edge e_cd connects cond_bb to dcall_bb, etc; note the first letters. */
+ e_cd = split_block (cond_bb, cond_stmt);
+ dcall_bb = e_cd->dest;
+ dcall_bb->count = count;
+
+ e_di = split_block (dcall_bb, dcall_stmt);
+ icall_bb = e_di->dest;
+ icall_bb->count = all - count;
+
+ /* Do not disturb existing EH edges from the indirect call. */
+ if (!stmt_ends_bb_p (icall_stmt))
+ e_ij = split_block (icall_bb, icall_stmt);
+ else
+ {
+ e_ij = find_fallthru_edge (icall_bb->succs);
+ /* The indirect call might be noreturn. */
+ if (e_ij != NULL)
+ {
+ e_ij->probability = REG_BR_PROB_BASE;
+ e_ij->count = all - count;
+ e_ij = single_pred_edge (split_edge (e_ij));
+ }
+ }
+ if (e_ij != NULL)
+ {
+ join_bb = e_ij->dest;
+ join_bb->count = all;
+ }