- tree op;
- tree tmp1, tmp2, tmp3;
- tree label_decl1 = create_artificial_label ();
- tree label_decl2 = create_artificial_label ();
- tree label_decl3 = create_artificial_label ();
- tree label_decl4 = create_artificial_label ();
- tree label_decl5 = create_artificial_label ();
- tree label1, label2, label3, label4, label5;
- tree stmt1, stmt2, stmt3, stmt4;
- tree bb1end, bb2end, bb3end, bb4end, bb5end;
- tree ref1 = tree_coverage_counter_ref (tag, base);
- tree ref2 = tree_coverage_counter_ref (tag, base + 1);
- tree ref3 = tree_coverage_counter_ref (tag, base + 2);
- basic_block bb2, bb3, bb4, bb5, bb6;
- tree stmt = value->hvalue.tree.stmt;
- block_stmt_iterator bsi = bsi_for_stmt (stmt);
- basic_block bb = bb_for_stmt (stmt);
- tree optype;
-
- op = stmt;
- if (TREE_CODE (stmt) == RETURN_EXPR
- && TREE_OPERAND (stmt, 0)
- && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
- op = TREE_OPERAND (stmt, 0);
- /* op == MODIFY_EXPR */
- op = TREE_OPERAND (op, 1);
- /* op == TRUNC_DIV or TRUNC_MOD */
- op = TREE_OPERAND (op, 1);
- /* op == denominator */
- optype = TREE_TYPE (op);
-
- /* Check if the stored value matches. */
- tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- tmp2 = create_tmp_var (optype, "PROF");
- tmp3 = create_tmp_var (optype, "PROF");
- stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref1);
- stmt2 = build2 (MODIFY_EXPR, optype, tmp2,
- build1 (NOP_EXPR, optype, tmp1));
- stmt3 = build2 (MODIFY_EXPR, optype, tmp3, op);
- stmt4 = build3 (COND_EXPR, void_type_node,
- build2 (EQ_EXPR, boolean_type_node, tmp2, tmp3),
- build1 (GOTO_EXPR, void_type_node, label_decl4),
- 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;
-
- /* Does not match; check whether the counter is zero. */
- label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
- tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
- stmt2 = build3 (COND_EXPR, void_type_node,
- build2 (EQ_EXPR, boolean_type_node, tmp1, integer_zero_node),
- build1 (GOTO_EXPR, void_type_node, label_decl3),
- build1 (GOTO_EXPR, void_type_node, label_decl2));
- bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
- bb2end = stmt2;
-
- /* Counter is not zero yet, decrement. */
- label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
- tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
- stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
- build (MINUS_EXPR, GCOV_TYPE_NODE,
- tmp1, integer_one_node));
- stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp2);
- bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
- bb3end = stmt3;
-
- /* Counter was zero, store new value. */
- label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
- tmp1 = create_tmp_var (optype, "PROF");
- tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- stmt1 = build2 (MODIFY_EXPR, optype, tmp1, op);
- stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
- build1 (NOP_EXPR, GCOV_TYPE_NODE, tmp1));
- stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref1, tmp2);
- bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
- bb4end = stmt3;
- /* (fall through) */
-
- /* Increment counter. */
- label4 = build1 (LABEL_EXPR, void_type_node, label_decl4);
- tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
- stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
- build (PLUS_EXPR, GCOV_TYPE_NODE,
- tmp1, integer_one_node));
- stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp2);
- bsi_insert_before (&bsi, label4, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
- bb5end = stmt3;
-
- /* Increment the counter of all executions; this seems redundant given
- that we have counts for edges in cfg, but it may happen that some
- optimization will change the counts for the block (either because
- it is unable to update them correctly, or because it will duplicate
- the block or its part). */
- label5 = build1 (LABEL_EXPR, void_type_node, label_decl5);
- tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
- stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref3);
- stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
- build (PLUS_EXPR, GCOV_TYPE_NODE,
- tmp1, integer_one_node));
- stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref3, tmp2);
- bsi_insert_before (&bsi, label5, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
- bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
-
- /* Now fix up the CFG. */
- bb2 = (split_block (bb, bb1end))->dest;
- bb3 = (split_block (bb2, bb2end))->dest;
- bb4 = (split_block (bb3, bb3end))->dest;
- bb5 = (split_block (bb4, bb4end))->dest;
- bb6 = (split_block (bb5, bb5end))->dest;
-
- EDGE_SUCC (bb, 0)->flags &= ~EDGE_FALLTHRU;
- EDGE_SUCC (bb, 0)->flags |= EDGE_FALSE_VALUE;
- make_edge (bb, bb5, EDGE_TRUE_VALUE);
-
- EDGE_SUCC (bb2, 0)->flags &= ~EDGE_FALLTHRU;
- EDGE_SUCC (bb2, 0)->flags |= EDGE_FALSE_VALUE;
- make_edge (bb2, bb4, EDGE_TRUE_VALUE);
-
- remove_edge (EDGE_SUCC (bb3, 0));
- make_edge (bb3, bb6, EDGE_FALLTHRU);
+ gimple stmt = value->hvalue.stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ tree ref_ptr = tree_coverage_counter_addr (tag, base);
+ gimple call;
+ tree val;
+
+ ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+ true, NULL_TREE, true, GSI_SAME_STMT);
+ val = prepare_instrumented_value (&gsi, value);
+ call = gimple_build_call (tree_one_value_profiler_fn, 2, ref_ptr, val);
+ gsi_insert_before (&gsi, call, GSI_NEW_STMT);
+ add_abnormal_goto_call_edges (gsi);
+}
+
+
+/* Output instructions as GIMPLE trees for code to find the most
+ common called function in indirect call.
+ VALUE is the call expression whose indirect callee is profiled.
+ TAG is the tag of the section for counters, BASE is offset of the
+ counter position. */
+
+static void
+tree_gen_ic_profiler (histogram_value value, unsigned tag, unsigned base)
+{
+ tree tmp1;
+ gimple stmt1, stmt2, stmt3;
+ gimple stmt = value->hvalue.stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ tree ref_ptr = tree_coverage_counter_addr (tag, base);
+
+ ref_ptr = force_gimple_operand_gsi (&gsi, ref_ptr,
+ true, NULL_TREE, true, GSI_SAME_STMT);
+
+ /* Insert code:
+
+ __gcov_indirect_call_counters = get_relevant_counter_ptr ();
+ __gcov_indirect_call_callee = (void *) indirect call argument;
+ */
+
+ tmp1 = create_tmp_var (ptr_void, "PROF");
+ stmt1 = gimple_build_assign (ic_gcov_type_ptr_var, ref_ptr);
+ stmt2 = gimple_build_assign (tmp1, unshare_expr (value->hvalue.value));
+ stmt3 = gimple_build_assign (ic_void_ptr_var, tmp1);
+
+ gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
+ gsi_insert_before (&gsi, stmt2, GSI_SAME_STMT);
+ gsi_insert_before (&gsi, stmt3, GSI_SAME_STMT);