OSDN Git Service

* config/cpu/s390/atomicity.h (__exchange_and_add): Add "memory"
[pf3gnuchains/gcc-fork.git] / gcc / tree-profile.c
1 /* Calculate branch probabilities, and basic block execution counts.
2    Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
3    2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
4    Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
5    based on some ideas from Dain Samples of UC Berkeley.
6    Further mangling by Bob Manson, Cygnus Support.
7    Converted to use trees by Dale Johannesen, Apple Computer.
8
9 This file is part of GCC.
10
11 GCC is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation; either version 2, or (at your option) any later
14 version.
15
16 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
17 WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with GCC; see the file COPYING.  If not, write to the Free
23 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24 02111-1307, USA.  */
25
26 /* Generate basic block profile instrumentation and auxiliary files.
27    Tree-based version.  See profile.c for overview.  */
28
29 #include "config.h"
30 #include "system.h"
31 #include "coretypes.h"
32 #include "tm.h"
33 #include "rtl.h"
34 #include "flags.h"
35 #include "output.h"
36 #include "regs.h"
37 #include "expr.h"
38 #include "function.h"
39 #include "toplev.h"
40 #include "coverage.h"
41 #include "tree.h"
42 #include "tree-flow.h"
43 #include "tree-dump.h"
44 #include "tree-pass.h"
45 #include "timevar.h"
46 #include "value-prof.h"
47
48 \f
49
50 /* Do initialization work for the edge profiler.  */
51
52 static void
53 tree_init_edge_profiler (void)
54 {
55 }
56
57 /* Output instructions as GIMPLE trees to increment the edge 
58    execution count, and insert them on E.  We rely on 
59    bsi_insert_on_edge to preserve the order.  */
60
61 static void
62 tree_gen_edge_profiler (int edgeno, edge e)
63 {
64   tree tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
65   tree tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
66   tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
67   tree stmt1 = build (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref);
68   tree stmt2 = build (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
69                       build (PLUS_EXPR, GCOV_TYPE_NODE, 
70                              tmp1, integer_one_node));
71   tree stmt3 = build (MODIFY_EXPR, GCOV_TYPE_NODE, ref, tmp2);
72   bsi_insert_on_edge (e, stmt1);
73   bsi_insert_on_edge (e, stmt2);
74   bsi_insert_on_edge (e, stmt3);
75 }
76
77 /* Output instructions as GIMPLE trees to increment the interval histogram 
78    counter.  VALUE is the expression whose value is profiled.  TAG is the 
79    tag of the section for counters, BASE is offset of the counter position.  */
80
81 static void
82 tree_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
83 {
84   tree op, op1, op2, op1copy, op2copy;
85   tree tmp1, tmp2, tmp3, val, index;
86   tree label_decl2, label_decl3, label_decl4, label_decl5, label_decl6;
87   edge e12, e23, e34, e45, e56;
88   tree label2, label3, label4, label5, label6;
89   tree stmt1, stmt2, stmt3, stmt4;
90   /* Initializations are to prevent bogus uninitialized warnings. */
91   tree bb1end = NULL_TREE, bb2end = NULL_TREE, bb3end = NULL_TREE;
92   tree bb4end = NULL_TREE, bb5end = NULL_TREE;
93   tree ref = tree_coverage_counter_ref (tag, base), ref2;
94   basic_block bb2, bb3, bb4, bb5, bb6;
95   tree stmt = value->hvalue.tree.stmt;
96   block_stmt_iterator bsi = bsi_for_stmt (stmt);
97   basic_block bb = bb_for_stmt (stmt);
98   tree optype;
99
100   op = stmt;
101   if (TREE_CODE (stmt) == RETURN_EXPR
102       && TREE_OPERAND (stmt, 0)
103       && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
104     op = TREE_OPERAND (stmt, 0);
105   /* op == MODIFY_EXPR */
106   op = TREE_OPERAND (op, 1);
107   /* op == TRUNC_DIV or TRUNC_MOD */
108   op1 = TREE_OPERAND (op, 0);
109   op2 = TREE_OPERAND (op, 1);
110   optype = TREE_TYPE (op);
111
112   /* Blocks:
113      Original = 1 
114      For 2nd compare = 2
115      Normal case, neither more nor less = 3
116      More = 4
117      Less = 5
118      End = 6  */
119   label_decl2 = create_artificial_label ();
120   label_decl3 = create_artificial_label ();
121   label_decl4 = create_artificial_label ();
122   label_decl5 = create_artificial_label ();
123   label_decl6 = create_artificial_label ();
124
125   /* Do not evaluate op1 or op2 more than once.  Probably
126      volatile loads are the only things that could cause
127      a problem, but this is harmless in any case.  */
128   op1copy = create_tmp_var (optype, "PROF");
129   op2copy = create_tmp_var (optype, "PROF");
130   stmt1 = build2 (MODIFY_EXPR, optype, op1copy, op1);
131   stmt2 = build2 (MODIFY_EXPR, optype, op2copy, op2);
132   TREE_OPERAND (op, 0) = op1copy;
133   TREE_OPERAND (op, 1) = op2copy;
134
135   val = create_tmp_var (optype, "PROF");
136   stmt3 = build2 (MODIFY_EXPR, optype, val,
137                   build2 (TRUNC_DIV_EXPR, optype, op1copy, op2copy));
138   stmt4 = build2 (MODIFY_EXPR, optype, val,
139                   build2 (MINUS_EXPR, optype, val,
140                                 build_int_cst (optype, value->hdata.intvl.int_start)));
141   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
142   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
143   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
144   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
145
146   index = create_tmp_var (GCOV_TYPE_NODE, "PROF");
147
148   /* Check for too big.  */
149   stmt1 = build3 (COND_EXPR, void_type_node,
150             build2 (GE_EXPR, boolean_type_node, val,
151                         build_int_cst (optype, value->hdata.intvl.steps)),
152             build1 (GOTO_EXPR, void_type_node, label_decl4),
153             build1 (GOTO_EXPR, void_type_node, label_decl2));
154   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
155   bb1end = stmt1;
156
157   /* Check for too small.  */
158   label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
159   bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
160   stmt1 = build3 (COND_EXPR, void_type_node,
161             build2 (LT_EXPR, boolean_type_node, val, integer_zero_node),
162             build1 (GOTO_EXPR, void_type_node, label_decl5),
163             build1 (GOTO_EXPR, void_type_node, label_decl3));
164   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
165   bb2end = stmt1;
166
167   /* Normal case, within range. */
168   label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
169   bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
170   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
171                     build1 (NOP_EXPR, GCOV_TYPE_NODE, val));
172   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
173   bb3end = stmt1;
174
175   /* Too big */
176   label4 = build1 (LABEL_EXPR, void_type_node, label_decl4);
177   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
178                     build_int_cst (GCOV_TYPE_NODE, value->hdata.intvl.steps));
179   bsi_insert_before (&bsi, label4, BSI_SAME_STMT);
180   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
181   bb4end = stmt1;
182
183   /* Too small */
184   label5 = build1 (LABEL_EXPR, void_type_node, label_decl5);
185   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
186                     build_int_cst (GCOV_TYPE_NODE, value->hdata.intvl.steps + 1));
187   bsi_insert_before (&bsi, label5, BSI_SAME_STMT);
188   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
189   bb5end = stmt1;
190
191   /* Increment appropriate counter. */
192   label6 = build1 (LABEL_EXPR, void_type_node, label_decl6);
193   bsi_insert_before (&bsi, label6, BSI_SAME_STMT);
194
195   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
196   tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
197   tmp3 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
198   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, 
199                     build2 (PLUS_EXPR, GCOV_TYPE_NODE, index, 
200                             TREE_OPERAND (ref, 1)));
201   TREE_OPERAND (ref, 1) = tmp1;
202   /* Make a copy to avoid sharing complaints. */
203   ref2 = build4 (ARRAY_REF, TREE_TYPE (ref), TREE_OPERAND (ref, 0), 
204                 TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2), 
205                 TREE_OPERAND (ref, 3));
206
207   stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, ref);
208   stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp3, 
209                     build2 (PLUS_EXPR, GCOV_TYPE_NODE, tmp2, integer_one_node));
210   stmt4 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp3);
211   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
212   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
213   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
214   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
215
216   /* Now fix up the CFG. */
217   /* 1->2,4; 2->3,5; 3->6; 4->6; 5->6 */
218   e12 = split_block (bb, bb1end);
219   bb2 = e12->dest;
220   e23 = split_block (bb2, bb2end);
221   bb3 = e23->dest;
222   e34 = split_block (bb3, bb3end);
223   bb4 = e34->dest;
224   e45 = split_block (bb4, bb4end);
225   bb5 = e45->dest;
226   e56 = split_block (bb5, bb5end);
227   bb6 = e56->dest;
228
229   e12->flags &= ~EDGE_FALLTHRU;
230   e12->flags |= EDGE_FALSE_VALUE;
231   make_edge (bb, bb4, EDGE_TRUE_VALUE);
232   e23->flags &= ~EDGE_FALLTHRU;
233   e23->flags |= EDGE_FALSE_VALUE;
234   make_edge (bb2, bb5, EDGE_TRUE_VALUE);
235   remove_edge (e34);
236   make_edge (bb3, bb6, EDGE_FALLTHRU);
237   remove_edge (e45);
238   make_edge (bb4, bb6, EDGE_FALLTHRU);
239 }
240
241 /* Output instructions as GIMPLE trees to increment the power of two histogram 
242    counter.  VALUE is the expression whose value is profiled.  TAG is the tag 
243    of the section for counters, BASE is offset of the counter position.  */
244
245 static void
246 tree_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
247 {
248   tree op;
249   tree tmp1, tmp2, tmp3;
250   tree index, denom;
251   tree label_decl1 = create_artificial_label ();
252   tree label_decl2 = create_artificial_label ();
253   tree label_decl3 = create_artificial_label ();
254   tree label1, label2, label3;
255   tree stmt1, stmt2, stmt3, stmt4;
256   tree bb1end, bb2end, bb3end;
257   tree ref = tree_coverage_counter_ref (tag, base), ref2;
258   basic_block bb2, bb3, bb4;
259   tree stmt = value->hvalue.tree.stmt;
260   block_stmt_iterator bsi = bsi_for_stmt (stmt);
261   basic_block bb = bb_for_stmt (stmt);
262   tree optype, optypesigned, optypeunsigned;
263
264   op = stmt;
265   if (TREE_CODE (stmt) == RETURN_EXPR
266       && TREE_OPERAND (stmt, 0)
267       && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
268     op = TREE_OPERAND (stmt, 0);
269   /* op == MODIFY_EXPR */
270   op = TREE_OPERAND (op, 1);
271   /* op == TRUNC_DIV or TRUNC_MOD */
272   op = TREE_OPERAND (op, 1);
273   /* op == denominator */
274   optype = TREE_TYPE (op);
275   if (TYPE_UNSIGNED (optype))
276     {
277       /* Right shift must be unsigned. */
278       optypeunsigned = optype;
279       optypesigned = build_distinct_type_copy (optype);
280       TYPE_UNSIGNED (optypesigned) = false;
281     }
282   else
283     {
284       /* Compare to zero must be signed. */
285       optypesigned = optype;
286       optypeunsigned = build_distinct_type_copy (optype);
287       TYPE_UNSIGNED (optypeunsigned) = true;
288     }
289
290   /* Set up variables and check if denominator is negative when considered
291      as signed.  */
292   index = create_tmp_var (GCOV_TYPE_NODE, "PROF");
293   denom = create_tmp_var (optype, "PROF");
294   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, integer_zero_node);
295   stmt2 = build2 (MODIFY_EXPR, optype, denom, op);
296   if (optypesigned == optype)
297     {
298       tmp1 = denom;
299       stmt3 = NULL_TREE;
300     }
301   else
302     {
303       tmp1 = create_tmp_var (optypesigned, "PROF");
304       stmt3 = build2 (MODIFY_EXPR, optypesigned, tmp1,
305                             build1 (NOP_EXPR, optypesigned, denom));
306     }
307   stmt4 = build3 (COND_EXPR, void_type_node,
308                 build2 (LE_EXPR, boolean_type_node, tmp1, integer_zero_node),
309                 build1 (GOTO_EXPR, void_type_node, label_decl3),
310                 build1 (GOTO_EXPR, void_type_node, label_decl1));
311   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
312   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
313   if (stmt3)
314     bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
315   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
316   bb1end = stmt4;
317
318   /* Nonnegative.  Check if denominator is power of 2. */
319   label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
320   tmp1 = create_tmp_var (optype, "PROF");
321   tmp2 = create_tmp_var (optype, "PROF");
322   stmt1 = build2 (MODIFY_EXPR, optype, tmp1,
323                     build2 (PLUS_EXPR, optype, denom, integer_minus_one_node));
324   stmt2 = build2 (MODIFY_EXPR, optype, tmp2,
325                     build2 (BIT_AND_EXPR, optype, tmp1, denom));
326   stmt3 = build3 (COND_EXPR, void_type_node, 
327                 build2 (NE_EXPR, boolean_type_node, tmp2, integer_zero_node),
328                 build1 (GOTO_EXPR, void_type_node, label_decl3),
329                 build1 (GOTO_EXPR, void_type_node, label_decl2));
330   bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
331   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
332   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
333   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
334   bb2end = stmt3;
335
336   /* Loop.  Increment index, shift denominator, repeat if denominator nonzero. */
337   label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
338   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, index, 
339                     build2 (PLUS_EXPR, GCOV_TYPE_NODE, index, integer_one_node));
340   if (optypeunsigned == optype)
341     {
342       tmp1 = denom;
343       stmt2 = NULL_TREE;
344     }
345   else
346     {
347       tmp1 = create_tmp_var (optypeunsigned, "PROF");
348       stmt2 = build2 (MODIFY_EXPR, optypeunsigned, tmp1,
349                         build1 (NOP_EXPR, optypeunsigned, denom));
350     }
351   stmt3 = build2 (MODIFY_EXPR, optype, denom,
352                     build2 (RSHIFT_EXPR, optype, tmp1, integer_one_node));
353   stmt4 = build3 (COND_EXPR, void_type_node, 
354                 build2 (NE_EXPR, boolean_type_node, denom, integer_zero_node),
355                 build1 (GOTO_EXPR, void_type_node, label_decl2),
356                 build1 (GOTO_EXPR, void_type_node, label_decl3));
357   bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
358   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
359   if (stmt2)
360     bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
361   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
362   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
363   bb3end = stmt4;
364
365   /* Increment the appropriate counter.  */
366   label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
367   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
368   tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
369   tmp3 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
370   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, 
371                     build2 (PLUS_EXPR, GCOV_TYPE_NODE, index, TREE_OPERAND (ref, 1)));
372   TREE_OPERAND (ref, 1) = tmp1;
373   /* Make a copy to avoid sharing complaints. */
374   ref2 = build4 (ARRAY_REF, TREE_TYPE (ref), TREE_OPERAND (ref, 0), 
375                 TREE_OPERAND (ref, 1), TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
376   stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, ref);
377   stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp3, 
378                     build2 (PLUS_EXPR, GCOV_TYPE_NODE, tmp2, integer_one_node));
379   stmt4 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp3);
380   bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
381   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
382   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
383   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
384   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
385
386   /* Now fix up the CFG. */
387   bb2 = (split_block (bb, bb1end))->dest;
388   bb3 = (split_block (bb2, bb2end))->dest;
389   bb4 = (split_block (bb3, bb3end))->dest;
390
391   EDGE_SUCC (bb, 0)->flags &= ~EDGE_FALLTHRU;
392   EDGE_SUCC (bb, 0)->flags |= EDGE_FALSE_VALUE;
393   make_edge (bb, bb4, EDGE_TRUE_VALUE);
394
395   EDGE_SUCC (bb2, 0)->flags &= ~EDGE_FALLTHRU;
396   EDGE_SUCC (bb2, 0)->flags |= EDGE_FALSE_VALUE;
397   make_edge (bb2, bb4, EDGE_TRUE_VALUE);
398
399   EDGE_SUCC (bb3, 0)->flags &= ~EDGE_FALLTHRU;
400   EDGE_SUCC (bb3, 0)->flags |= EDGE_FALSE_VALUE;
401   make_edge (bb3, bb3, EDGE_TRUE_VALUE);
402 }
403
404 /* Output instructions as GIMPLE trees for code to find the most common value.
405    VALUE is the expression whose value is profiled.  TAG is the tag of the
406    section for counters, BASE is offset of the counter position.  */
407
408 static void
409 tree_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
410 {
411   tree op;
412   tree tmp1, tmp2, tmp3;
413   tree label_decl1 = create_artificial_label ();
414   tree label_decl2 = create_artificial_label ();
415   tree label_decl3 = create_artificial_label ();
416   tree label_decl4 = create_artificial_label ();
417   tree label_decl5 = create_artificial_label ();
418   tree label1, label2, label3, label4, label5;
419   tree stmt1, stmt2, stmt3, stmt4;
420   tree bb1end, bb2end, bb3end, bb4end, bb5end;
421   tree ref1 = tree_coverage_counter_ref (tag, base);
422   tree ref2 = tree_coverage_counter_ref (tag, base + 1);
423   tree ref3 = tree_coverage_counter_ref (tag, base + 2);
424   basic_block bb2, bb3, bb4, bb5, bb6;
425   tree stmt = value->hvalue.tree.stmt;
426   block_stmt_iterator bsi = bsi_for_stmt (stmt);
427   basic_block bb = bb_for_stmt (stmt);
428   tree optype;
429
430   op = stmt;
431   if (TREE_CODE (stmt) == RETURN_EXPR
432       && TREE_OPERAND (stmt, 0)
433       && TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
434     op = TREE_OPERAND (stmt, 0);
435   /* op == MODIFY_EXPR */
436   op = TREE_OPERAND (op, 1);
437   /* op == TRUNC_DIV or TRUNC_MOD */
438   op = TREE_OPERAND (op, 1);
439   /* op == denominator */
440   optype = TREE_TYPE (op);
441
442   /* Check if the stored value matches. */
443   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
444   tmp2 = create_tmp_var (optype, "PROF");
445   tmp3 = create_tmp_var (optype, "PROF");
446   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref1);
447   stmt2 = build2 (MODIFY_EXPR, optype, tmp2, 
448                     build1 (NOP_EXPR, optype, tmp1));
449   stmt3 = build2 (MODIFY_EXPR, optype, tmp3, op);
450   stmt4 = build3 (COND_EXPR, void_type_node, 
451                 build2 (EQ_EXPR, boolean_type_node, tmp2, tmp3),
452                 build1 (GOTO_EXPR, void_type_node, label_decl4),
453                 build1 (GOTO_EXPR, void_type_node, label_decl1));
454   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
455   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
456   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
457   bsi_insert_before (&bsi, stmt4, BSI_SAME_STMT);
458   bb1end = stmt4;
459
460   /* Does not match; check whether the counter is zero. */
461   label1 = build1 (LABEL_EXPR, void_type_node, label_decl1);
462   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
463   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
464   stmt2 = build3 (COND_EXPR, void_type_node, 
465                 build2 (EQ_EXPR, boolean_type_node, tmp1, integer_zero_node),
466                 build1 (GOTO_EXPR, void_type_node, label_decl3), 
467                 build1 (GOTO_EXPR, void_type_node, label_decl2));
468   bsi_insert_before (&bsi, label1, BSI_SAME_STMT);
469   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
470   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
471   bb2end = stmt2;
472
473   /* Counter is not zero yet, decrement. */
474   label2 = build1 (LABEL_EXPR, void_type_node, label_decl2);
475   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
476   tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
477   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
478   stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
479                       build (MINUS_EXPR, GCOV_TYPE_NODE, 
480                              tmp1, integer_one_node));
481   stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp2);
482   bsi_insert_before (&bsi, label2, BSI_SAME_STMT);
483   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
484   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
485   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
486   bb3end = stmt3;
487
488   /* Counter was zero, store new value. */
489   label3 = build1 (LABEL_EXPR, void_type_node, label_decl3);
490   tmp1 = create_tmp_var (optype, "PROF");
491   tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
492   stmt1 = build2 (MODIFY_EXPR, optype, tmp1, op);
493   stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2, 
494                         build1 (NOP_EXPR, GCOV_TYPE_NODE, tmp1));
495   stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref1, tmp2);
496   bsi_insert_before (&bsi, label3, BSI_SAME_STMT);
497   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
498   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
499   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
500   bb4end = stmt3;
501   /* (fall through) */
502
503   /* Increment counter.  */
504   label4 = build1 (LABEL_EXPR, void_type_node, label_decl4);
505   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
506   tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
507   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref2);
508   stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
509                       build (PLUS_EXPR, GCOV_TYPE_NODE, 
510                              tmp1, integer_one_node));
511   stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref2, tmp2);
512   bsi_insert_before (&bsi, label4, BSI_SAME_STMT);
513   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
514   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
515   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
516   bb5end = stmt3;
517
518   /* Increment the counter of all executions; this seems redundant given
519      that we have counts for edges in cfg, but it may happen that some
520      optimization will change the counts for the block (either because
521      it is unable to update them correctly, or because it will duplicate
522      the block or its part).  */
523   label5 = build1 (LABEL_EXPR, void_type_node, label_decl5);
524   tmp1 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
525   tmp2 = create_tmp_var (GCOV_TYPE_NODE, "PROF");
526   stmt1 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp1, ref3);
527   stmt2 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, tmp2,
528                       build (PLUS_EXPR, GCOV_TYPE_NODE, 
529                              tmp1, integer_one_node));
530   stmt3 = build2 (MODIFY_EXPR, GCOV_TYPE_NODE, ref3, tmp2);
531   bsi_insert_before (&bsi, label5, BSI_SAME_STMT);
532   bsi_insert_before (&bsi, stmt1, BSI_SAME_STMT);
533   bsi_insert_before (&bsi, stmt2, BSI_SAME_STMT);
534   bsi_insert_before (&bsi, stmt3, BSI_SAME_STMT);
535
536   /* Now fix up the CFG. */
537   bb2 = (split_block (bb, bb1end))->dest;
538   bb3 = (split_block (bb2, bb2end))->dest;
539   bb4 = (split_block (bb3, bb3end))->dest;
540   bb5 = (split_block (bb4, bb4end))->dest;
541   bb6 = (split_block (bb5, bb5end))->dest;
542
543   EDGE_SUCC (bb, 0)->flags &= ~EDGE_FALLTHRU;
544   EDGE_SUCC (bb, 0)->flags |= EDGE_FALSE_VALUE;
545   make_edge (bb, bb5, EDGE_TRUE_VALUE);
546
547   EDGE_SUCC (bb2, 0)->flags &= ~EDGE_FALLTHRU;
548   EDGE_SUCC (bb2, 0)->flags |= EDGE_FALSE_VALUE;
549   make_edge (bb2, bb4, EDGE_TRUE_VALUE);
550
551   remove_edge (EDGE_SUCC (bb3, 0));
552   make_edge (bb3, bb6, EDGE_FALLTHRU);
553 }
554
555 /* Output instructions as GIMPLE trees for code to find the most common value 
556    of a difference between two evaluations of an expression.
557    VALUE is the expression whose value is profiled.  TAG is the tag of the
558    section for counters, BASE is offset of the counter position.  */
559
560 static void
561 tree_gen_const_delta_profiler (histogram_value value ATTRIBUTE_UNUSED, 
562                                 unsigned tag ATTRIBUTE_UNUSED,
563                                 unsigned base ATTRIBUTE_UNUSED)
564 {
565   /* FIXME implement this.  */
566 #ifdef ENABLE_CHECKING
567   internal_error ("unimplemented functionality");
568 #endif
569   gcc_unreachable ();
570 }
571
572 /* Return 1 if tree-based profiling is in effect, else 0.
573    If it is, set up hooks for tree-based profiling.
574    Gate for pass_tree_profile.  */
575
576 static bool
577 do_tree_profiling (void)
578 {
579   if (flag_tree_based_profiling
580       && (profile_arc_flag || flag_test_coverage || flag_branch_probabilities))
581     {
582       tree_register_profile_hooks ();
583       tree_register_value_prof_hooks ();
584       return true;
585     }
586   return false;
587 }
588
589 /* Return the file on which profile dump output goes, if any.  */
590
591 static FILE *tree_profile_dump_file (void) {
592   return dump_file;
593 }
594
595 static void
596 tree_profiling (void)
597 {
598   branch_prob ();
599   if (flag_branch_probabilities
600       && flag_profile_values
601       && flag_value_profile_transformations)
602     value_profile_transformations ();
603   /* The above could hose dominator info.  Currently there is
604      none coming in, this is a safety valve.  It should be
605      easy to adjust it, if and when there is some.  */
606   free_dominance_info (CDI_DOMINATORS);
607   free_dominance_info (CDI_POST_DOMINATORS);
608 }
609
610 struct tree_opt_pass pass_tree_profile = 
611 {
612   "tree_profile",                       /* name */
613   do_tree_profiling,                    /* gate */
614   tree_profiling,                       /* execute */
615   NULL,                                 /* sub */
616   NULL,                                 /* next */
617   0,                                    /* static_pass_number */
618   TV_BRANCH_PROB,                       /* tv_id */
619   PROP_gimple_leh | PROP_cfg,           /* properties_required */
620   PROP_gimple_leh | PROP_cfg,           /* properties_provided */
621   0,                                    /* properties_destroyed */
622   0,                                    /* todo_flags_start */
623   TODO_verify_stmts,                    /* todo_flags_finish */
624   0                                     /* letter */
625 };
626
627 struct profile_hooks tree_profile_hooks =
628 {
629   tree_init_edge_profiler,      /* init_edge_profiler */
630   tree_gen_edge_profiler,       /* gen_edge_profiler */
631   tree_gen_interval_profiler,   /* gen_interval_profiler */
632   tree_gen_pow2_profiler,       /* gen_pow2_profiler */
633   tree_gen_one_value_profiler,  /* gen_one_value_profiler */
634   tree_gen_const_delta_profiler,/* gen_const_delta_profiler */
635   tree_profile_dump_file        /* profile_dump_file */
636 };