* gcc-plugin.h (enum plugin_event): Add PLUGIN_ALL_IPA_PASSES_START,
[official-gcc.git] / gcc / function-instrumentation.c
blob0dab235c2b86e382a5d8cbc548cff55ac3fd0d3a
1 /* Function Instrumentation.
2 Copyright (C) 2009 by Cupertino Miranda, Shuangde Huang, Liang Peng
3 INRIA Futurs, France; ICT, China;
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "tree.h"
27 #include "rtl.h"
28 #include "tm_p.h"
29 #include "hard-reg-set.h"
30 #include "basic-block.h"
31 #include "output.h"
32 #include "diagnostic.h"
33 #include "tree-flow.h"
34 #include "tree-dump.h"
35 #include "tree-pass.h"
36 #include "timevar.h"
37 #include "cfgloop.h"
38 #include "flags.h"
39 #include "tree-inline.h"
40 #include "cgraph.h"
41 #include "ipa-prop.h"
42 #include "opts.h"
43 #include "tree-iterator.h"
44 #include "gimple.h"
45 #include "toplev.h"
46 #include "highlev-plugin-internal.h"
48 /* Info for function instrumentation. */
49 instrinfo idi;
51 static bool
52 is_it_instrumentable (struct cgraph_node *cg_func)
54 if (cgraph_function_body_availability (cg_func) == AVAIL_NOT_AVAILABLE)
55 return false;
56 else
57 return true;
60 static void
61 freeinstrinfo (instrinfo idi)
63 /* free instrumentation info. */
64 int i;
65 for(i=0; i<idi.numofinstrfun; i++)
67 free (*(idi.instrument_function_list + i));
68 free (*(idi.function_filename_list + i));
69 free (*(idi.timer1 + i));
70 free (*(idi.timer2 + i));
72 free (idi.instrument_function_list);
73 free (idi.function_filename_list);
74 free (idi.timer1);
75 free (idi.timer2);
78 static bool
79 is_in_instrument_list (const char *func_name, const char *file_name,
80 int *nid)
82 int i = 0;
83 for(i = 0; i < idi.numofinstrfun; i++)
85 if (strcmp (func_name, *(idi.instrument_function_list + i)) == 0
86 && strcmp (file_name, *(idi.function_filename_list + i)) == 0)
88 *nid = i;
89 return true;
92 return false;
95 static void
96 add_timer_begin (struct cgraph_node *cg_func, char *funname, int cloned)
98 gimple_stmt_iterator gsi;
99 struct function * func = NULL;
100 gimple_seq gp_seq = NULL;
101 gimple stmt = NULL;
102 basic_block bb = NULL;
103 location_t location;
105 tree decl = cg_func->decl;
106 tree ftype = build_function_type (void_type_node, void_list_node);
107 tree func_decl = build_fn_decl (funname, ftype);
108 tree call_expr = build_function_call_expr (func_decl, NULL_TREE);
109 location = DECL_SOURCE_LOCATION(decl);
110 DECL_SOURCE_LOCATION(func_decl) = location;
112 /*convert the call_expr (tree) to gimple_seq(gp_seq)*/
113 gimplify_stmt(&call_expr, &gp_seq);
115 func = DECL_STRUCT_FUNCTION (decl);
116 bb = ENTRY_BLOCK_PTR_FOR_FUNCTION (func)->next_bb;
117 gsi = gsi_start_bb(bb);
118 if(cloned == 1)
119 gsi_insert_seq_after (&gsi, gp_seq, GSI_NEW_STMT);
120 else
121 gsi_insert_seq_before (&gsi, gp_seq, GSI_NEW_STMT);
122 stmt = gsi_stmt (gsi);
123 gimple_set_location (stmt, location);
125 cgraph_create_edge (cg_func, cgraph_node (func_decl),
126 stmt,
127 bb->count, CGRAPH_FREQ_MAX, bb->loop_depth);
131 static void
132 add_timer_end (struct cgraph_node *cg_func, char *funname)
134 edge e;
135 edge_iterator ei;
136 gimple_stmt_iterator gsi;
137 struct function *func = NULL;
138 gimple stmt = NULL;
139 gimple_seq gp_seq = NULL;
140 tree decl, ftype, func_decl, call_expr;
141 location_t location;
143 decl = cg_func->decl;
144 ftype = build_function_type (void_type_node, void_list_node);
145 func_decl = build_fn_decl (funname, ftype);
147 func = DECL_STRUCT_FUNCTION (decl);
148 location = func->function_end_locus;
149 DECL_SOURCE_LOCATION(func_decl) = location;
151 FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FUNCTION (func)->preds)
153 gsi = gsi_last_bb (e->src);
155 call_expr = build_function_call_expr (func_decl, NULL_TREE);
156 gimplify_stmt(&call_expr, &gp_seq);
158 if (gimple_code(gsi_stmt (gsi)) == GIMPLE_RETURN)
159 gsi_insert_seq_before (&gsi, gp_seq, GSI_NEW_STMT);
160 else
161 gsi_insert_seq_after (&gsi, gp_seq, GSI_NEW_STMT);
163 stmt = gsi_stmt (gsi);
164 gimple_set_location (stmt, location);
165 gp_seq = NULL;
167 cgraph_create_edge (cg_func, cgraph_node (func_decl),
168 stmt,
169 e->src->count, CGRAPH_FREQ_MAX,
170 e->src->loop_depth);
174 static unsigned int
175 exec_instrument_functions (void)
177 struct cgraph_node *node;
178 struct function *saved_cfun, *func;
179 int nid = -1;
180 char *beginname = NULL, *endname = NULL;
181 saved_cfun = cfun;
182 idi.numofinstrfun = 0;
184 register_event_parameter("instr_info", &idi, EP_VOID);
185 call_plugin_event("load_instr_config");
186 unregister_event_parameter("instr_info");
188 if (idi.numofinstrfun == 0)
190 fprintf (stderr, "No infomation for instrumentation pass\n");
191 return 0;
194 /* Perform instrument to functions. */
195 for (node = cgraph_nodes; node; node = node->next)
197 const char *node_name = NULL;
198 const char *file_name = NULL;
199 func = DECL_STRUCT_FUNCTION (node->decl);
200 set_cfun (func);
201 node_name = IDENTIFIER_POINTER (DECL_NAME (node->decl));
202 file_name = expand_location(DECL_SOURCE_LOCATION (node->decl)).file;
204 if (is_in_instrument_list (node_name, file_name, &nid)
205 && is_it_instrumentable(node))
207 int flag_cloned = 0;
208 if (*(idi.cloned + nid) == '1')
209 flag_cloned = 1;
210 if (getenv ("ICI_VERBOSE") != NULL)
211 printf("Now instrument function: %s \n", node_name);
212 beginname = (char *) alloca (strlen (node_name) +
213 strlen (*(idi.timer1 + nid)));
214 if ((*(idi.timer1 + nid))[0] == '_')
215 sprintf (beginname, "%s%s", node_name, *(idi.timer1 + nid));
216 else
217 sprintf (beginname, "%s", *(idi.timer1 + nid));
219 add_timer_begin (node, beginname, flag_cloned);
221 endname = (char *) alloca (strlen (node_name) +
222 strlen (*(idi.timer2 + nid)));
223 if ((*(idi.timer2 + nid))[0] == '_')
224 sprintf (endname, "%s%s", node_name, *(idi.timer2 + nid));
225 else
226 sprintf (endname, "%s", *(idi.timer2 + nid));
228 add_timer_end (node, endname);
232 set_cfun(saved_cfun);
233 freeinstrinfo (idi);
234 return 0;
237 static bool
238 gate_instrument_functions(void)
240 return flag_api_instrument_functions;
243 struct gimple_opt_pass pass_instrument_functions = {
245 SIMPLE_IPA_PASS ,
246 "instrumentation", /* name */
247 gate_instrument_functions, /* gate */
248 exec_instrument_functions, /* execute */
249 NULL, /* sub */
250 NULL, /* next */
251 0, /* static_pass_number */
252 0, /* tv_id */
253 0, /* properties_required */
254 0, /* properties_provided */
255 0, /* properties_destroyed */
256 0, /* todo_flags_start */
257 TODO_dump_cgraph | TODO_verify_flow, /* todo_flags_finish */