1 /* Call site versioning
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
23 #include "coretypes.h"
25 #include "langhooks.h"
32 #include "tree-flow.h"
33 #include "tree-inline.h"
34 #include "splay-tree.h"
35 #include "tree-inline-aux.h"
36 #include "tree-pass.h"
40 typedef struct loop_info
42 basic_block preheader
;
43 basic_block postheader
;
44 basic_block loop_begin
;
48 #define SWITCH_BLOCKS_NUM 6
49 #define DUPLICATE_BLOCKS_NUM 6
50 typedef struct duplicate_info
53 basic_block switch_blocks
[SWITCH_BLOCKS_NUM
];
55 basic_block duplicate_blocks
[DUPLICATE_BLOCKS_NUM
];
56 basic_block merge_block
;
60 type_to_consider (tree type
);
61 bool arg_defined_in_statement_p (tree stmt
, tree argument
);
63 has_defs (tree call
, basic_block
* switch_blocks
, int switch_blocks_num
);
65 loop_find_call (struct loop_info
*loopinfo
);
70 has_defs (tree call
, basic_block
* switch_blocks
, int switch_blocks_num
)
75 block_stmt_iterator bsi
;
76 gcc_assert (TREE_CODE (call
) == CALL_EXPR
);
77 arg
= TREE_OPERAND (call
, 1);
79 /* fprintf (dump_file, "In has_defs\n"); */
81 for (i
= 0; arg
!= NULL_TREE
&& i
< switch_blocks_num
; arg
= TREE_CHAIN (arg
), i
++)
83 /*fprintf (dump_file, "In for. i = %d\n",i);*/
86 if (type_to_consider (arg
))
88 /* fprintf (dump_file, "Exited type to consider!\n");*/
90 while (j
< switch_blocks_num
&& switch_blocks
[j
] != NULL
)
93 /* fprintf (dump_file, "Reading basic block %d",j); */
94 current
= switch_blocks
[j
];
95 /* fprintf (dump_file, "Read %d",j); */
96 for (bsi
= bsi_start (/*switch_blocks[j])*/current
); !bsi_end_p (bsi
);
99 /* fprintf (dump_file, "In while's for !\n"); */
100 stmt
= bsi_stmt (bsi
);
101 if (arg_defined_in_statement_p (stmt
, arg
))
103 /* fprintf (dump_file, "Found !!!\n"); */
111 /*fprintf (dump_file, "Exiting !!!\n"); */
117 type_to_consider (tree type
)
119 /* fprintf (dump_file, "In type to consider!\n"); */
121 /* Strip the *'s off. */
122 type
= TREE_TYPE(TREE_VALUE(type
));
123 /* while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
124 type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
126 switch (TREE_CODE (type
))
133 case QUAL_UNION_TYPE
:
147 bool arg_defined_in_statement_p (tree stmt
, tree argument
)
149 if (TREE_CODE(stmt
) == MODIFY_EXPR
)
150 if (TREE_OPERAND (stmt
, 0) == TREE_VALUE(argument
))
156 loop_find_call (struct loop_info
*loopinfo
)
158 basic_block currloop
[2], bb
= NULL
;
161 block_stmt_iterator bsi
;
162 tree call
, stmt
, decl
;
163 currloop
[0] = loopinfo
->loop_begin
;
164 currloop
[1] = loopinfo
->loop_end
;
165 /* fprintf (dump_file, "check loop bb %d \n", 4444); */
167 for (count
= 0; count
< loopnumbb
; count
++)
169 if ((bb
= currloop
[count
]) != NULL
)
170 for (bsi
= bsi_start (bb
); !bsi_end_p (bsi
); bsi_next (&bsi
))
172 /* fprintf (dump_file, "hi check loop bb %d \n", bb->index); */
173 stmt
= bsi_stmt (bsi
);
174 call
= get_call_expr_in (stmt
);
175 if (call
&& (decl
= get_callee_fndecl (call
)))
177 /* fprintf (dump_file,"call bb %d \n", bb->index); */
189 check_single_loop (basic_block bb
, loop_info
*li
)
197 fprintf (dump_file
, "check loop bb %d \n", bb
->index
);
199 if (EDGE_COUNT (bb
->succs
) != 2)
202 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
208 fprintf (dump_file
, "check succs bb1 %d \n", bb1
->index
);
210 if ((EDGE_COUNT (bb1
->preds
) != 1) ||
211 (EDGE_COUNT (bb1
->succs
) != 1) ||
212 (EDGE_SUCC (bb1
, 0)->dest
) != bb
)
214 li
->postheader
= bb1
;
235 fprintf (dump_file
, "postheader %d\n", li
->postheader
->index
);
236 fprintf (dump_file
, "header %d\n", li
->loop_begin
->index
);
237 fprintf (dump_file
, "latch %d\n", li
->loop_end
->index
);
240 if (EDGE_COUNT (bb
->preds
) != 2)
242 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
246 (bb1
== li
->loop_end
))
254 if (!li
->preheader
||
255 EDGE_COUNT (li
->preheader
->preds
) < 2 ||
256 EDGE_COUNT (li
->preheader
->succs
) != 1)
260 fprintf (dump_file
, "prehader %d\n", li
->preheader
->index
);
262 if (li
->preheader
->next_bb
!= li
->loop_end
||
263 li
->loop_end
->next_bb
!= li
->loop_begin
||
264 li
->loop_begin
->next_bb
!= li
->postheader
)
271 find_switch_blocks (loop_info
*li
, duplicate_info
*di
)
280 FOR_EACH_EDGE (e
, ei
, bb1
->preds
)
282 if (i
>= SWITCH_BLOCKS_NUM
)
284 if (EDGE_COUNT (e
->src
->succs
) != 1)
286 di
->switch_blocks
[i
++] = e
->src
;
294 di
->duplicate_blocks
[i
++] = bb1
;
295 di
->duplicate_blocks
[i
++] = li
->loop_end
;
296 di
->duplicate_blocks
[i
++] = li
->loop_begin
;
297 di
->n_duplicate_bb
= i
;
301 for (i
= 0; i
< di
->n_switch_bb
; i
++)
302 fprintf (dump_file
, "switch %d\n",di
->switch_blocks
[i
]->index
);
303 for (i
= 0; i
< di
->n_duplicate_bb
; i
++)
304 fprintf (dump_file
, "duplicate %d\n",di
->duplicate_blocks
[i
]->index
);
307 /* di->merge_block = di->duplicate_blocks [di->n_duplicate_bb - 1]->next_bb; remove after CHECK */
308 di
->merge_block
= li
->postheader
;
311 for (i
= 0; i
< di
->n_switch_bb
; i
++)
314 block_stmt_iterator bsi
;
316 bsi
= bsi_last (di
->switch_blocks
[i
]);
318 /* enable after CHECK.
320 goto_stmt = bsi_stmt (bsi);
321 if (TREE_CODE (goto_stmt) == GOTO_EXPR)
324 e
= split_block (di
->switch_blocks
[i
], bsi_stmt (bsi
));
332 duplicate_code_path (duplicate_info
*di
, int index
, inline_data
*id
)
334 gcov_type count_scale
;
338 basic_block after_switch
;
341 fprintf (dump_file
, "path %d\n", di
->switch_blocks
[index
]->index
);
343 if (di
->switch_blocks
[index
]->count
)
344 count_scale
= (REG_BR_PROB_BASE
* count_scale
345 / di
->switch_blocks
[index
]->count
);
348 if (di
->switch_blocks
[index
]->frequency
)
349 frequency_scale
= (REG_BR_PROB_BASE
* frequency_scale
350 / di
->switch_blocks
[index
]->frequency
);
352 di
->duplicate_blocks
[0]->prev_bb
->aux
= di
->switch_blocks
[index
];
353 di
->duplicate_blocks
[di
->n_duplicate_bb
- 1]->next_bb
->aux
=
354 EDGE_SUCC (di
->switch_blocks
[index
], 0)->dest
;
357 id
->decl_map
= splay_tree_new (splay_tree_compare_pointers
,
360 /* CHECK lang_hooks.tree_inlining.auto_var_in_fn_p */
361 for (j
= 0; j
< di
->n_duplicate_bb
; j
++)
364 fprintf (dump_file
, "copy bb %d\n", di
->duplicate_blocks
[j
]->index
);
365 di
->duplicate_blocks
[j
]->aux
=
366 copy_bb (id
, di
->duplicate_blocks
[j
], frequency_scale
, count_scale
);
368 fprintf (dump_file
, "duplicate bb %d\n", ((basic_block
) (di
->duplicate_blocks
[j
]->aux
))->index
);
371 for (j
= 0; j
< di
->n_duplicate_bb
; j
++)
374 fprintf (dump_file
, "edges bb %d\n", di
->duplicate_blocks
[j
]->index
);
376 copy_edges_for_bb (di
->duplicate_blocks
[j
], count_scale
);
379 after_switch
= EDGE_SUCC (di
->switch_blocks
[index
], 0)->dest
;
380 redirect_edge_succ (EDGE_SUCC (di
->switch_blocks
[index
], 0),
381 di
->duplicate_blocks
[0]->aux
);
382 /* EDGE_SUCC (after_switch, 0)->flags &= ~EDGE_FALLTHRU; CHECK */
383 redirect_edge_succ (EDGE_SUCC (after_switch
, 0),
384 di
->duplicate_blocks
[di
->n_duplicate_bb
- 1]->next_bb
);
385 for (j
= 0; j
< di
->n_duplicate_bb
; j
++)
386 di
->duplicate_blocks
[j
]->aux
= NULL
;
387 di
->duplicate_blocks
[0]->prev_bb
->aux
= NULL
;
388 di
->duplicate_blocks
[di
->n_duplicate_bb
- 1]->next_bb
->aux
= NULL
;
390 splay_tree_delete (id
->decl_map
);
395 duplicate_code (duplicate_info
*di
, inline_data
*id
, struct function
*cfun
)
400 for (i
= 0; i
< di
->n_switch_bb
; i
++)
403 block_stmt_iterator bsi
;
405 bsi
= bsi_last (di
->switch_blocks
[i
]);
407 /* enable after CHECK.
409 goto_stmt = bsi_stmt (bsi);
410 if (TREE_CODE (goto_stmt) == GOTO_EXPR)
413 e
= split_block (di
->switch_blocks
[i
], bsi_stmt (bsi
));
417 id
->current_node
= id
->node
= cgraph_node (current_function_decl
);
418 id
->caller
= id
->callee
= current_function_decl
;
419 id
->callee_cfun
= cfun
;
420 id
->eh_region_offset
= 0;
422 id
->versioning_p
= 1;
427 id
->copybb_only_p
= 1;
428 for (i
= 0; i
< di
->n_switch_bb
; i
++)
429 duplicate_code_path (di
, i
, id
);
433 callsite_versioning (struct function
*cfun
)
443 /* printf ("enter callsite versioning \n"); */
447 li
.loop_begin
= NULL
;
449 li
.postheader
= NULL
;
450 found
= check_single_loop (bb
, &li
) ;
454 fprintf (dump_file
, "***loop info*** \n");
457 di
.n_duplicate_bb
= 0;
458 di
.merge_block
= NULL
;
459 check
= find_switch_blocks (&li
, &di
);
463 fprintf (dump_file
, "***duplicate info*** \n");
465 call_insn
= loop_find_call (&li
) ;
466 if (call_insn
== NULL_TREE
) continue;
468 if(has_defs (call_insn
, di
.switch_blocks
, di
.n_switch_bb
))
470 /* fprintf (dump_file, "Ura! Check passed \n"); */
471 memset (&id
, 0, sizeof (id
));
472 duplicate_code (&di
, &id
, cfun
);
474 fprintf (dump_file
, "***success*** \n");
476 /*else fprintf (dump_file, "Noooo! \n"); */
478 /* int_args = call_find_args (call_insn); */
479 /* if (has_defs (di.switch_blocks, int_args)) */
481 /* printf ("exit callsite versioning \n"); */
487 struct cgraph_node
*node
;
489 /* printf("enter cv \n"); */
490 for (node
= cgraph_nodes
; node
; node
= node
->next
)
494 if (DECL_SAVED_TREE (node
->decl
) == NULL
)
500 temp_fn
= current_function_decl
;
501 current_function_decl
= node
->decl
;
502 push_cfun (DECL_STRUCT_FUNCTION (node
->decl
));
503 /* bitmap_obstack_initialize (NULL); */
504 tree_register_cfg_hooks ();
505 callsite_versioning (DECL_STRUCT_FUNCTION (node
->decl
));
506 free_dominance_info (CDI_DOMINATORS
);
507 free_dominance_info (CDI_POST_DOMINATORS
);
509 current_function_decl
= temp_fn
;
511 /* printf("exit cv \n"); */
514 /* Gate for the call versionin ogptimization. */
516 cgraph_gate_cv (void)
521 struct tree_opt_pass pass_cv
= {
523 cgraph_gate_cv
, /* gate */
524 cv_driver
, /* execute */
527 0, /* static_pass_number */
529 0, /* properties_required */
530 PROP_trees
, /* properties_provided */
531 0, /* properties_destroyed */
532 0, /* todo_flags_start */
533 TODO_dump_func
, /* todo_flags_finish */