1 /* Generic function cloning.
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 generic cloning. */
52 is_it_main (struct cgraph_node
*cg_func
)
54 if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (cg_func
->decl
)), "MAIN__"))
56 if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (cg_func
->decl
)), "main"))
63 has_variable_arguments(tree decl
)
65 return DECL_STRUCT_FUNCTION(decl
)->stdarg
== 1;
69 is_it_clonable (struct cgraph_node
*cg_func
)
71 tree decl
= cg_func
->decl
;
73 /* TODO Are this enough */
74 if (cg_func
->global
.inlined_to
)
77 if (is_it_main (cg_func
))
80 if (cgraph_function_body_availability (cg_func
) == AVAIL_NOT_AVAILABLE
)
83 if (flags_from_decl_or_type (decl
) & ECF_NORETURN
)
86 /* ??? Mismatch between the returned type and the result declaration. */
87 if (TREE_TYPE (TREE_TYPE (decl
)) != TREE_TYPE (DECL_RESULT (decl
)))
90 /* it has variable number of arguments */
91 if (has_variable_arguments(decl
))
98 freecloneinfo (cloneinfo cdi
)
100 /* free clone info. */
103 free (cdi
.external_libraries
);
104 for(i
= 0, num
= 0; i
<cdi
.numofclonefun
; num
+= *(cdi
.clones
+ i
), i
++)
106 free (*(cdi
.clone_function_list
+ i
));
107 free (*(cdi
.function_filename_list
+ i
));
108 free (*(cdi
.clone_extension
+ i
));
109 free (*(cdi
.adaptation_function
+ i
));
110 for(j
=0; j
<*(cdi
.clones
+ i
); j
++)
111 free (*(cdi
.clone_option
+ num
+ j
));
113 free (cdi
.clone_function_list
);
114 free (cdi
.function_filename_list
);
115 free (cdi
.clone_extension
);
116 free (cdi
.adaptation_function
);
118 free (cdi
.clone_option
);
122 is_in_clone_list (const char *func_name
, const char *file_name
,
126 for(i
= 0; i
< cdi
.numofclonefun
; i
++)
128 if (strcmp (func_name
, *(cdi
.clone_function_list
+ i
)) == 0
129 && strcmp (file_name
, *(cdi
.function_filename_list
+ i
)) == 0)
139 set_function_invalid (const char *func_name
)
142 for(i
= 0; i
< cdi
.numofclonefun
; i
++)
144 if (strcmp (func_name
, *(cdi
.clone_function_list
+ i
)) == 0)
146 strcpy (*(cdi
.clone_function_list
+ i
), "");
153 find_clone_options (char *funcname
, int *nid
)
156 char *clone_name
= NULL
;
158 for(i
= 0; i
< cdi
.numofclonefun
; i
++)
160 for(j
= 0; j
< cdi
.clones
[i
]; j
++)
163 clone_name
= (char *) alloca
164 (strlen (*(cdi
.clone_function_list
+ i
))
165 + strlen (*(cdi
.clone_extension
+ i
))
167 sprintf (clone_name
, "%s%s_%d",
168 *(cdi
.clone_function_list
+ i
),
169 *(cdi
.clone_extension
+ i
), j
);
170 if (strcmp (funcname
, clone_name
) == 0)
180 /* Function for parsing adaptation arguments and desirable functions. */
182 parse_clone_option (char *text
, unsigned int *argc
)
184 unsigned int i
, size
;
192 size
= strlen (text
);
193 for (i
= 0; i
< size
; i
++)
202 argv
= (char **) xmalloc (sizeof (char *) * (*argc
));
205 for (i
= 1; i
< (*argc
); i
++)
208 start
+= (strlen (start
) + 1);
215 extern tree
mf_mark (tree
);
217 get_arguments (tree tree_list
)
219 tree args
= NULL_TREE
;
223 args
= tree_cons (NULL_TREE
, tree_list
, args
);
224 tree_list
= TREE_CHAIN (tree_list
);
227 return nreverse (args
);
231 add_call_to_clones (struct cgraph_node
*orig
, int nid
)
233 tree decl
, ftype
, args
, select_func
, select_call
, clone_call
, index
;
234 tree body_label
, call_label
, return_var
;
235 char *select_name
, *clone_fname
;
236 VEC (tree
,heap
) *labels
;
237 basic_block first_bb
, entry
, call_block
, body_block
;
238 gimple gp_switch_expr
, gp_clone_expr
, gp_return_expr
,
239 gp_select_expr
, gp_body_label_expr
, gp_call_label_expr
;
240 struct function
*func
;
241 gimple_stmt_iterator gsi
;
242 struct cgraph_node
*clone
= NULL
;
243 struct cgraph_node
*curr_node
= NULL
;
244 struct cgraph_node
*select_node
;
245 struct cgraph_edge
*cge
;
252 /* decl of orig function node. */
254 location
= DECL_SOURCE_LOCATION(decl
);
256 /* Get arguments of original function. */
257 func
= DECL_STRUCT_FUNCTION (decl
);
258 args
= get_arguments (DECL_ARGUMENTS (decl
));
260 first_bb
= ENTRY_BLOCK_PTR_FOR_FUNCTION (func
)->next_bb
;
261 gsi
= gsi_start_bb (first_bb
);
264 /* build call to adaptation_function. */
265 ftype
= build_function_type (unsigned_type_node
, void_list_node
);
266 select_name
= (char *) alloca
267 (strlen((IDENTIFIER_POINTER (DECL_NAME (decl
))))
269 if ((*(cdi
.adaptation_function
+ nid
))[0] == '_')
270 sprintf (select_name
, "%s%s",IDENTIFIER_POINTER (DECL_NAME (decl
)),
271 *(cdi
.adaptation_function
+ nid
));
273 sprintf (select_name
, "%s", *(cdi
.adaptation_function
+ nid
));
275 select_func
= build_fn_decl (select_name
, ftype
);
276 DECL_SOURCE_LOCATION(select_func
) = location
;
277 select_call
= build_function_call_expr (select_func
, NULL_TREE
);
278 gp_select_expr
= gimple_build_call_from_tree (select_call
);
279 gimple_set_location (gp_select_expr
, location
);
282 index
= create_tmp_var (unsigned_type_node
, "index");
283 gimple_call_set_lhs (gp_select_expr
, index
);
285 DECL_EXTERNAL (select_func
) = 1;
286 TREE_PUBLIC (select_func
) = 1;
287 select_node
= cgraph_node (select_func
);
288 cgraph_mark_needed_node (select_node
);
289 select_node
->local
.externally_visible
= 1;
290 select_node
->local
.local
= 0;
291 cgraph_create_edge (orig
, select_node
, gp_select_expr
,
293 CGRAPH_FREQ_MAX
, first_bb
->loop_depth
);
294 cgraph_mark_needed_node (select_node
);
296 /* default label of switch. */
297 body_label
= build3 (CASE_LABEL_EXPR
, void_type_node
, NULL_TREE
,
298 NULL_TREE
, create_artificial_label ());
299 gp_body_label_expr
= gimple_build_label(CASE_LABEL(body_label
));
300 gimple_set_location (gp_body_label_expr
, location
);
302 /* switch label vector : labels. */
303 labels
= VEC_alloc (tree
, heap
, cdi
.clones
[nid
]);
305 gsi_insert_before (&gsi
, gp_select_expr
, GSI_SAME_STMT
);
306 body_edge
= split_block (entry
, gp_select_expr
);
307 body_block
= body_edge
->dest
;
308 first_bb
= body_edge
->src
;
309 entry
->flags
|= BB_REACHABLE
;
310 body_block
->flags
|= BB_REACHABLE
;
311 body_edge
->flags
|= EDGE_EXECUTABLE
;
312 body_edge
->flags
&= ~EDGE_FALLTHRU
;
314 /* For each clone. */
315 for(i
= 0; i
< cdi
.clones
[nid
]; i
++)
318 /*get the clone node from function name. */
319 clone_fname
= (char *) alloca
320 (strlen (IDENTIFIER_POINTER (DECL_NAME (decl
)))
321 + strlen (*(cdi
.clone_extension
+ nid
))
323 sprintf (clone_fname
, "%s%s_%d",
324 IDENTIFIER_POINTER (DECL_NAME (decl
)),
325 *(cdi
.clone_extension
+ nid
), i
);
327 for(curr_node
= cgraph_nodes
; curr_node
;
328 curr_node
= curr_node
->next
)
330 if (strcmp (IDENTIFIER_POINTER (DECL_NAME (curr_node
->decl
)),
341 call_block
= create_basic_block (NULL
, NULL
, first_bb
);
343 /* Set gsi to current block. */
344 gsi
= gsi_start_bb (call_block
);
346 /* build clone call expr, and return expr. */
347 clone_call
= build_function_call_expr (clone
->decl
, args
);
348 gp_clone_expr
= gimple_build_call_from_tree (clone_call
);
349 gimple_set_location (gp_clone_expr
, location
);
351 if(TREE_TYPE (TREE_TYPE (decl
)) != void_type_node
)
353 if (aggregate_value_p (DECL_RESULT(decl
), decl
)
354 && !is_gimple_reg_type (TREE_TYPE (DECL_RESULT (decl
)))
355 && !DECL_NAME (DECL_RESULT(decl
)))
356 return_var
= DECL_RESULT (decl
);
359 create_tmp_var (TREE_TYPE (DECL_RESULT (decl
)), "ret");
360 DECL_CONTEXT (return_var
) = decl
;
361 gimple_call_set_lhs (gp_clone_expr
, return_var
);
362 gp_return_expr
= gimple_build_return(return_var
);
366 gp_return_expr
= gimple_build_return(NULL
);
369 gimple_set_location (gp_return_expr
, location
);
372 clone expr and return expr to current block. */
373 call_label
= build3 (CASE_LABEL_EXPR
, void_type_node
,
374 build_int_cst (integer_type_node
, i
+1),
375 NULL_TREE
, create_artificial_label ());
376 gp_call_label_expr
= gimple_build_label(CASE_LABEL(call_label
));
377 gimple_set_location (gp_call_label_expr
, location
);
379 gsi_insert_before (&gsi
, gp_call_label_expr
, GSI_SAME_STMT
);
380 gsi_insert_before (&gsi
, gp_clone_expr
, GSI_SAME_STMT
);
382 SET_EXPR_LOCUS (clone_call, gimple_location_ptr (first_stmt (first_bb)));
383 TREE_BLOCK (clone_call) = TREE_BLOCK (select_call); */
385 gsi_insert_before (&gsi
, gp_return_expr
, GSI_SAME_STMT
);
387 VEC_safe_insert (tree
, heap
, labels
, i
, call_label
);
389 /* CGRAPH corrections. */
391 cge
= cgraph_create_edge (orig
, cgraph_node (clone
->decl
),
393 first_bb
->count
, CGRAPH_FREQ_MAX
,
394 first_bb
->loop_depth
);
395 cge
->inline_failed
= "Clonned function";
396 cgraph_mark_needed_node (cgraph_node (clone
->decl
));
398 /* CFG corrections. */
399 call_block
->flags
|= BB_REACHABLE
;
400 call_block
->flags
|= BB_DISABLE_SCHEDULE
;
401 make_edge (entry
, call_block
, EDGE_EXECUTABLE
);
402 make_edge (call_block
, EXIT_BLOCK_PTR
, 0);
403 update_stmt (gp_call_label_expr
);
404 update_stmt (gp_clone_expr
);
405 update_stmt (gp_return_expr
);
408 entry
->flags
|= BB_DISABLE_SCHEDULE
;
409 body_block
->flags
|= BB_DISABLE_SCHEDULE
;
411 /* insert default label. */
412 gsi
= gsi_start_bb (body_block
);
413 gsi_insert_before (&gsi
, gp_body_label_expr
, GSI_SAME_STMT
);
415 CASE_LOW (body_label
) = NULL
;
416 if (!VEC_empty (tree
, labels
))
417 sort_case_labels (labels
);
419 gp_switch_expr
= gimple_build_switch_vec (index
, body_label
, labels
);
420 gimple_set_location (gp_switch_expr
, location
);
421 gsi
= gsi_start_bb (first_bb
);
422 gsi_insert_after (&gsi
, gp_switch_expr
, GSI_SAME_STMT
);
424 /* redirect incomming edges from entry to body_block. */
429 FOR_EACH_EDGE (e
, ei
, entry
->preds
)
431 if (e
->src
!= ENTRY_BLOCK_PTR_FOR_FUNCTION (func
))
433 make_edge (e
->src
, body_block
, e
->flags
);
440 update_stmt (gp_select_expr
);
441 update_stmt (gp_body_label_expr
);
442 update_stmt (gp_switch_expr
);
446 exec_clone_functions (void)
448 struct cgraph_node
*node
;
449 struct function
*saved_cfun
, *func
;
453 int nid
= -1, optid
= -1;
455 int saved_flag_strict_aliasing
, saved_flag_pcc_struct_return
,
456 saved_flag_omit_frame_pointer
, saved_flag_asynchronous_unwind_tables
;
457 char *output_name
= NULL
;
460 cdi
.numofclonefun
= 0;
462 register_event_parameter("clone_info", &cdi
, EP_VOID
);
463 call_plugin_event("load_clone_config");
464 unregister_event_parameter("clone_info");
466 if (cdi
.numofclonefun
== 0)
468 fprintf (stderr
, "No infomation for function cloning pass\n");
472 /* Perform cloning to functions */
473 for (node
= cgraph_nodes
; node
; node
= node
->next
)
475 const char *node_name
= NULL
;
476 const char *file_name
= NULL
;
477 func
= DECL_STRUCT_FUNCTION (node
->decl
);
479 node_name
= IDENTIFIER_POINTER (DECL_NAME (node
->decl
));
480 file_name
= expand_location(DECL_SOURCE_LOCATION (node
->decl
)).file
;
481 /*is cfun in the clone_list*/
482 if(is_in_clone_list(node_name
, file_name
, &nid
))
484 if (is_it_clonable (node
))
486 struct cgraph_node
*clone_node
= NULL
;
487 if (getenv ("ICI_VERBOSE") != NULL
)
488 printf("Now clone function: %s \n", node_name
);
489 /* Do not clone virtual clone function. */
490 for(i
= 0; i
< cdi
.numofclonefun
; i
++)
492 if (!strcmp (node_name
+ (strlen (node_name
) -
493 strlen (*(cdi
.clone_extension
+ i
))),
494 *(cdi
.clone_extension
+ i
)))
496 printf ("%s is a virtual clone function\n",
501 if( i
< cdi
.numofclonefun
)
504 DECL_UNINLINABLE(node
->decl
) = 1;
505 for(i
= 0; i
< cdi
.clones
[nid
]; i
++)
507 set_cfun(DECL_STRUCT_FUNCTION (node
->decl
));
509 clone_node
= generic_cloning_cgraph_function_versioning (node
,
513 DECL_POSSIBLY_INLINED(clone_node
->decl
) = 0;
515 /* The cloned function should not be inlined. */
516 clone_node
->local
.inlinable
= false;
517 DECL_UNINLINABLE(clone_node
->decl
) = 1;
519 /* Generate a new name for the new version. */
521 (char *) alloca (strlen
523 (DECL_NAME (node
->decl
)))
525 sprintf (output_name
, "%s%s_%d",
527 (DECL_NAME (node
->decl
)),
528 *(cdi
.clone_extension
+ nid
), i
);
530 DECL_NAME (clone_node
->decl
) =
531 get_identifier (output_name
);
533 /* Create a new SYMBOL_REF rtx for the new name. */
535 if (DECL_RTL (node
->decl
) != NULL
)
537 SET_DECL_RTL (clone_node
->decl
,
540 XEXP (DECL_RTL (clone_node
->decl
), 0) =
541 gen_rtx_SYMBOL_REF( GET_MODE
546 (clone_node
->decl
)));
549 DECL_STRUCT_FUNCTION (clone_node
->decl
)
550 ->function_start_locus
= DECL_STRUCT_FUNCTION
551 (node
->decl
)->function_start_locus
;
553 fundecl
= clone_node
->decl
;
554 if (TREE_CODE (fundecl
) == FUNCTION_DECL
555 && find_clone_options (output_name
, &optid
))
557 struct cl_optimization cur_opts
;
559 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fundecl
);
561 /* Save current options. */
562 cl_optimization_save (&cur_opts
);
564 /* If we previously had some optimization options,
565 use them as the default. */
567 cl_optimization_restore (TREE_OPTIMIZATION (old_opts
));
569 /* Parse options, and update the vector. */
571 parse_clone_option (*(cdi
.clone_option
+ optid
), &argc
);
573 /* may need to preserve more in the future,
574 reference OPTIMIZATION_OPTIONS and OVERRIDE_OPTIONS */
575 saved_flag_strict_aliasing
= flag_strict_aliasing
;
576 saved_flag_omit_frame_pointer
= flag_omit_frame_pointer
;
577 saved_flag_pcc_struct_return
= flag_pcc_struct_return
;
578 saved_flag_asynchronous_unwind_tables
=
579 flag_asynchronous_unwind_tables
;
581 decode_options (argc
, (const char **) argv
);
583 /* Don't allow changing following flags. */
584 flag_omit_frame_pointer
= saved_flag_omit_frame_pointer
;
585 flag_asynchronous_unwind_tables
=
586 saved_flag_asynchronous_unwind_tables
;
587 flag_pcc_struct_return
= saved_flag_pcc_struct_return
;
588 flag_strict_aliasing
= saved_flag_strict_aliasing
;
590 DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fundecl
)
591 = build_optimization_node ();
593 /* Restore current options. */
594 cl_optimization_restore (&cur_opts
);
598 add_call_to_clones (node
, nid
);
602 printf("%s (in the clone list) can not be cloned!\n",
604 set_function_invalid(node_name
);
609 set_cfun(saved_cfun
);
615 gate_clone_functions(void)
617 return flag_api_clone_functions
;
620 struct gimple_opt_pass pass_clone_functions
= {
623 "generic_cloning", /* name */
624 gate_clone_functions
, /* gate */
625 exec_clone_functions
, /* execute */
628 0, /* static_pass_number */
630 0, /* properties_required */
631 0, /* properties_provided */
632 0, /* properties_destroyed */
633 0, /* todo_flags_start */
634 TODO_dump_cgraph
| TODO_verify_flow
, /* todo_flags_finish */