Small changes to remove go past a few of the bootstrap errors:
[official-gcc.git] / gcc / generic-cloning.c
blobfd3e4c6dca676ee0231f8c64cccd4b301ec17a36
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
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 generic cloning. */
49 cloneinfo cdi;
51 static inline bool
52 is_it_main (struct cgraph_node *cg_func)
54 if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (cg_func->decl)), "MAIN__"))
55 return true;
56 if (!strcmp (IDENTIFIER_POINTER (DECL_NAME (cg_func->decl)), "main"))
57 return true;
59 return false;
62 static bool
63 has_variable_arguments(tree decl)
65 return DECL_STRUCT_FUNCTION(decl)->stdarg == 1;
68 static bool
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)
75 return false;
77 if (is_it_main (cg_func))
78 return false;
80 if (cgraph_function_body_availability (cg_func) == AVAIL_NOT_AVAILABLE)
81 return false;
83 if (flags_from_decl_or_type (decl) & ECF_NORETURN)
84 return false;
86 /* ??? Mismatch between the returned type and the result declaration. */
87 if (TREE_TYPE (TREE_TYPE (decl)) != TREE_TYPE (DECL_RESULT (decl)))
88 return false;
90 /* it has variable number of arguments */
91 if (has_variable_arguments(decl))
92 return false;
94 return true;
97 static void
98 freecloneinfo (cloneinfo cdi)
100 /* free clone info. */
101 int i,j;
102 int num = 3;
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);
117 free (cdi.clones);
118 free (cdi.clone_option);
121 static bool
122 is_in_clone_list (const char *func_name, const char *file_name,
123 int *nid)
125 int i = 0;
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)
131 *nid = i;
132 return true;
135 return false;
138 static void
139 set_function_invalid (const char *func_name)
141 int i = 0;
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), "");
147 return;
152 static bool
153 find_clone_options (char *funcname, int *nid)
155 int i, j, cid;
156 char *clone_name = NULL;
157 cid = -1;
158 for(i = 0; i < cdi.numofclonefun; i++)
160 for(j = 0; j < cdi.clones[i]; j++)
162 cid ++;
163 clone_name = (char *) alloca
164 (strlen (*(cdi.clone_function_list + i))
165 + strlen (*(cdi.clone_extension + i))
166 + 64);
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)
172 *nid = cid;
173 return true;
177 return false;
180 /* Function for parsing adaptation arguments and desirable functions. */
181 static char **
182 parse_clone_option (char *text, unsigned int *argc)
184 unsigned int i, size;
185 char **argv;
186 char *start;
188 *argc = 0;
189 if (text[0] != 0)
190 *argc = 2;
192 size = strlen (text);
193 for (i = 0; i < size; i++)
195 if (text[i] == ' ')
197 text[i] = '\0';
198 (*argc)++;
202 argv = (char **) xmalloc (sizeof (char *) * (*argc));
204 start = text;
205 for (i = 1; i < (*argc); i++)
207 argv[i] = start;
208 start += (strlen (start) + 1);
211 return argv;
215 extern tree mf_mark (tree);
216 static tree
217 get_arguments (tree tree_list)
219 tree args = NULL_TREE;
221 while (tree_list)
223 args = tree_cons (NULL_TREE, tree_list, args);
224 tree_list = TREE_CHAIN (tree_list);
227 return nreverse (args);
230 static void
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;
246 edge body_edge, e;
247 edge_iterator ei;
248 int i;
249 bool removed;
250 location_t location;
252 /* decl of orig function node. */
253 decl = orig->decl;
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);
262 entry = 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))))
268 + 64);
269 if ((*(cdi.adaptation_function + nid))[0] == '_')
270 sprintf (select_name, "%s%s",IDENTIFIER_POINTER (DECL_NAME (decl)),
271 *(cdi.adaptation_function + nid));
272 else
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);
281 /* switch index. */
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,
292 first_bb->count,
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++)
317 clone = NULL;
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))
322 + 64);
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)),
331 clone_fname) == 0)
333 clone = curr_node;
334 break;
338 if (clone == NULL)
339 break;
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);
357 else
358 return_var =
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);
364 else
366 gp_return_expr = gimple_build_return(NULL);
369 gimple_set_location (gp_return_expr, location);
371 /* add switch label,
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),
392 gp_clone_expr,
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. */
425 removed = true;
426 while (removed)
428 removed = false;
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);
434 remove_edge (e);
435 removed = true;
436 break;
440 update_stmt (gp_select_expr);
441 update_stmt (gp_body_label_expr);
442 update_stmt (gp_switch_expr);
445 static unsigned int
446 exec_clone_functions (void)
448 struct cgraph_node *node;
449 struct function *saved_cfun, *func;
450 tree fundecl;
451 unsigned int argc;
452 char **argv;
453 int nid = -1, optid = -1;
454 int i;
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;
459 saved_cfun = cfun;
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");
469 return 0;
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);
478 set_cfun(func);
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",
497 node_name);
498 break;
501 if( i < cdi.numofclonefun)
502 continue;
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,
510 NULL,
511 NULL, 0);
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. */
520 output_name =
521 (char *) alloca (strlen
522 (IDENTIFIER_POINTER
523 (DECL_NAME (node->decl)))
524 + 64);
525 sprintf (output_name, "%s%s_%d",
526 IDENTIFIER_POINTER
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,
538 copy_rtx (DECL_RTL
539 (node->decl)));
540 XEXP (DECL_RTL (clone_node->decl), 0) =
541 gen_rtx_SYMBOL_REF( GET_MODE
542 (XEXP (DECL_RTL
543 (node->decl), 0)),
544 IDENTIFIER_POINTER
545 (DECL_NAME
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;
558 tree old_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. */
566 if (old_opts)
567 cl_optimization_restore (TREE_OPTIMIZATION (old_opts));
569 /* Parse options, and update the vector. */
570 argv =
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);
600 else
602 printf("%s (in the clone list) can not be cloned!\n",
603 node_name);
604 set_function_invalid(node_name);
609 set_cfun(saved_cfun);
610 freecloneinfo (cdi);
611 return 0;
614 static bool
615 gate_clone_functions(void)
617 return flag_api_clone_functions;
620 struct gimple_opt_pass pass_clone_functions = {
622 SIMPLE_IPA_PASS ,
623 "generic_cloning", /* name */
624 gate_clone_functions, /* gate */
625 exec_clone_functions, /* execute */
626 NULL, /* sub */
627 NULL, /* next */
628 0, /* static_pass_number */
629 0, /* tv_id */
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 */