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
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
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
24 #include "coretypes.h"
29 #include "hard-reg-set.h"
30 #include "basic-block.h"
32 #include "diagnostic.h"
33 #include "tree-flow.h"
34 #include "tree-dump.h"
35 #include "tree-pass.h"
39 #include "tree-inline.h"
43 #include "tree-iterator.h"
46 #include "highlev-plugin-internal.h"
48 /* Info for function instrumentation. */
52 is_it_instrumentable (struct cgraph_node
*cg_func
)
54 if (cgraph_function_body_availability (cg_func
) == AVAIL_NOT_AVAILABLE
)
61 freeinstrinfo (instrinfo idi
)
63 /* free instrumentation info. */
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
);
79 is_in_instrument_list (const char *func_name
, const char *file_name
,
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)
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
;
102 basic_block bb
= NULL
;
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
);
109 = build_function_call_expr (UNKNOWN_LOCATION
, func_decl
, NULL_TREE
);
110 location
= DECL_SOURCE_LOCATION(decl
);
111 DECL_SOURCE_LOCATION(func_decl
) = location
;
113 /*convert the call_expr (tree) to gimple_seq(gp_seq)*/
114 gimplify_stmt(&call_expr
, &gp_seq
);
116 func
= DECL_STRUCT_FUNCTION (decl
);
117 bb
= ENTRY_BLOCK_PTR_FOR_FUNCTION (func
)->next_bb
;
118 gsi
= gsi_start_bb(bb
);
120 gsi_insert_seq_after (&gsi
, gp_seq
, GSI_NEW_STMT
);
122 gsi_insert_seq_before (&gsi
, gp_seq
, GSI_NEW_STMT
);
123 stmt
= gsi_stmt (gsi
);
124 gimple_set_location (stmt
, location
);
126 cgraph_create_edge (cg_func
, cgraph_node (func_decl
),
128 bb
->count
, CGRAPH_FREQ_MAX
, bb
->loop_depth
);
133 add_timer_end (struct cgraph_node
*cg_func
, char *funname
)
137 gimple_stmt_iterator gsi
;
138 struct function
*func
= NULL
;
140 gimple_seq gp_seq
= NULL
;
141 tree decl
, ftype
, func_decl
, call_expr
;
144 decl
= cg_func
->decl
;
145 ftype
= build_function_type (void_type_node
, void_list_node
);
146 func_decl
= build_fn_decl (funname
, ftype
);
148 func
= DECL_STRUCT_FUNCTION (decl
);
149 location
= func
->function_end_locus
;
150 DECL_SOURCE_LOCATION(func_decl
) = location
;
152 FOR_EACH_EDGE (e
, ei
, EXIT_BLOCK_PTR_FOR_FUNCTION (func
)->preds
)
154 gsi
= gsi_last_bb (e
->src
);
157 = build_function_call_expr (UNKNOWN_LOCATION
, func_decl
, NULL_TREE
);
158 gimplify_stmt(&call_expr
, &gp_seq
);
160 if (gimple_code(gsi_stmt (gsi
)) == GIMPLE_RETURN
)
161 gsi_insert_seq_before (&gsi
, gp_seq
, GSI_NEW_STMT
);
163 gsi_insert_seq_after (&gsi
, gp_seq
, GSI_NEW_STMT
);
165 stmt
= gsi_stmt (gsi
);
166 gimple_set_location (stmt
, location
);
169 cgraph_create_edge (cg_func
, cgraph_node (func_decl
),
171 e
->src
->count
, CGRAPH_FREQ_MAX
,
177 exec_instrument_functions (void)
179 struct cgraph_node
*node
;
180 struct function
*saved_cfun
, *func
;
182 char *beginname
= NULL
, *endname
= NULL
;
184 idi
.numofinstrfun
= 0;
186 invoke_named_callbacks ("load_instr_config",
187 "instr_info", EP_VOID
, &idi
, EP_VOID
, NULL
);
189 if (idi
.numofinstrfun
== 0)
191 fprintf (stderr
, "No infomation for instrumentation pass\n");
195 /* Perform instrument to functions. */
196 for (node
= cgraph_nodes
; node
; node
= node
->next
)
198 const char *node_name
= NULL
;
199 const char *file_name
= NULL
;
200 func
= DECL_STRUCT_FUNCTION (node
->decl
);
202 node_name
= IDENTIFIER_POINTER (DECL_NAME (node
->decl
));
203 file_name
= expand_location(DECL_SOURCE_LOCATION (node
->decl
)).file
;
205 if (is_in_instrument_list (node_name
, file_name
, &nid
)
206 && is_it_instrumentable(node
))
209 if (*(idi
.cloned
+ nid
) == '1')
211 if (getenv ("ICI_VERBOSE") != NULL
)
212 printf("Now instrument function: %s \n", node_name
);
213 beginname
= (char *) alloca (strlen (node_name
) +
214 strlen (*(idi
.timer1
+ nid
)));
215 if ((*(idi
.timer1
+ nid
))[0] == '_')
216 sprintf (beginname
, "%s%s", node_name
, *(idi
.timer1
+ nid
));
218 sprintf (beginname
, "%s", *(idi
.timer1
+ nid
));
220 add_timer_begin (node
, beginname
, flag_cloned
);
222 endname
= (char *) alloca (strlen (node_name
) +
223 strlen (*(idi
.timer2
+ nid
)));
224 if ((*(idi
.timer2
+ nid
))[0] == '_')
225 sprintf (endname
, "%s%s", node_name
, *(idi
.timer2
+ nid
));
227 sprintf (endname
, "%s", *(idi
.timer2
+ nid
));
229 add_timer_end (node
, endname
);
233 set_cfun(saved_cfun
);
239 gate_instrument_functions(void)
241 return flag_api_instrument_functions
;
244 struct gimple_opt_pass pass_instrument_functions
= {
247 "instrumentation", /* name */
248 gate_instrument_functions
, /* gate */
249 exec_instrument_functions
, /* execute */
252 0, /* static_pass_number */
254 0, /* properties_required */
255 0, /* properties_provided */
256 0, /* properties_destroyed */
257 0, /* todo_flags_start */
258 TODO_dump_cgraph
| TODO_verify_flow
, /* todo_flags_finish */