OSDN Git Service

* g++.dg/parse/repo1.C: Use cleanup-repo-files.
[pf3gnuchains/gcc-fork.git] / gcc / rtl-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, 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
8 This file is part of GCC.
9
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GCC; see the file COPYING.  If not, write to the Free
22 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 02111-1307, USA.  */
24
25 /* Generate basic block profile instrumentation and auxiliary files.
26    RTL-based version.  See profile.c for overview.  */
27
28 #include "config.h"
29 #include "system.h"
30 #include "coretypes.h"
31 #include "tm.h"
32 #include "rtl.h"
33 #include "flags.h"
34 #include "output.h"
35 #include "regs.h"
36 #include "expr.h"
37 #include "function.h"
38 #include "toplev.h"
39 #include "coverage.h"
40 #include "value-prof.h"
41 #include "tree.h"
42 #include "ggc.h"
43
44 /* Do initialization work for the edge profiler.  */
45
46 static void
47 rtl_init_edge_profiler (void)
48 {
49   /* gen_edge_profiler calls safe_insert_insn_on_edge which needs
50      register liveness data to be available.  */
51   life_analysis (NULL, 0);
52 }
53
54 /* Output instructions as RTL to increment the edge execution count.  */
55
56 static void
57 rtl_gen_edge_profiler (int edgeno, edge e)
58 {
59   rtx ref = rtl_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno);
60   rtx tmp;
61   enum machine_mode mode = GET_MODE (ref);
62   rtx sequence;
63
64   start_sequence ();
65   ref = validize_mem (ref);
66
67   tmp = expand_simple_binop (mode, PLUS, ref, const1_rtx,
68                              ref, 0, OPTAB_WIDEN);
69
70   if (tmp != ref)
71     emit_move_insn (copy_rtx (ref), tmp);
72
73   sequence = get_insns ();
74   end_sequence ();
75   safe_insert_insn_on_edge (sequence, e);
76   rebuild_jump_labels (e->insns.r);
77 }
78
79 /* Output instructions as RTL to increment the interval histogram counter.
80    VALUE is the expression whose value is profiled.  TAG is the tag of the
81    section for counters, BASE is offset of the counter position.  */
82
83 static void
84 rtl_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
85 {
86   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
87   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
88   rtx mem_ref, tmp, tmp1, mr, val;
89   rtx sequence;
90   rtx more_label = gen_label_rtx ();
91   rtx less_label = gen_label_rtx ();
92   rtx end_of_code_label = gen_label_rtx ();
93   int per_counter = gcov_size / BITS_PER_UNIT;
94   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
95                    PREV_INSN (value->hvalue.rtl.insn));
96
97   start_sequence ();
98
99   if (value->hvalue.rtl.seq)
100     emit_insn (value->hvalue.rtl.seq);
101
102   mr = gen_reg_rtx (Pmode);
103
104   tmp = rtl_coverage_counter_ref (tag, base);
105   tmp = force_reg (Pmode, XEXP (tmp, 0));
106
107   val = expand_simple_binop (value->hvalue.rtl.mode, MINUS,
108                              copy_rtx (value->hvalue.rtl.value),
109                              GEN_INT (value->hdata.intvl.int_start),
110                              NULL_RTX, 0, OPTAB_WIDEN);
111
112     do_compare_rtx_and_jump (copy_rtx (val), GEN_INT (value->hdata.intvl.steps),
113                            GE, 0, value->hvalue.rtl.mode, NULL_RTX, NULL_RTX, 
114                            more_label);
115   do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, 
116                            value->hvalue.rtl.mode,
117                              NULL_RTX, NULL_RTX, less_label);
118
119   /* We are in range.  */
120   tmp1 = expand_simple_binop (value->hvalue.rtl.mode, MULT,
121                               copy_rtx (val), GEN_INT (per_counter),
122                               NULL_RTX, 0, OPTAB_WIDEN);
123   tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), tmp1, mr,
124                               0, OPTAB_WIDEN);
125   if (tmp1 != mr)
126     emit_move_insn (copy_rtx (mr), tmp1);
127
128       emit_jump_insn (gen_jump (end_of_code_label));
129       emit_barrier ();
130
131   /* Above the interval.  */
132       emit_label (more_label);
133       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
134                                   GEN_INT (per_counter * value->hdata.intvl.steps),
135                                   mr, 0, OPTAB_WIDEN);
136       if (tmp1 != mr)
137         emit_move_insn (copy_rtx (mr), tmp1);
138           emit_jump_insn (gen_jump (end_of_code_label));
139           emit_barrier ();
140
141   /* Below the interval.  */
142       emit_label (less_label);
143       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
144                         GEN_INT (per_counter * (value->hdata.intvl.steps +1)),
145                 mr, 0, OPTAB_WIDEN);
146       if (tmp1 != mr)
147         emit_move_insn (copy_rtx (mr), tmp1);
148
149     emit_label (end_of_code_label);
150
151   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
152
153   tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
154                              mem_ref, 0, OPTAB_WIDEN);
155
156   if (tmp != mem_ref)
157     emit_move_insn (copy_rtx (mem_ref), tmp);
158
159   sequence = get_insns ();
160   end_sequence ();
161   rebuild_jump_labels (sequence);
162   safe_insert_insn_on_edge (sequence, e);
163 }
164
165 /* Output instructions as RTL to increment the power of two histogram counter.
166    VALUE is the expression whose value is profiled.  TAG is the tag of the
167    section for counters, BASE is offset of the counter position.  */
168
169 static void
170 rtl_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
171 {
172   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
173   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
174   rtx mem_ref, tmp, mr, uval;
175   rtx sequence;
176   rtx end_of_code_label = gen_label_rtx ();
177   rtx loop_label = gen_label_rtx ();
178   int per_counter = gcov_size / BITS_PER_UNIT;
179   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
180                    PREV_INSN (value->hvalue.rtl.insn));
181
182   start_sequence ();
183
184   if (value->hvalue.rtl.seq)
185     emit_insn (value->hvalue.rtl.seq);
186
187   mr = gen_reg_rtx (Pmode);
188   tmp = rtl_coverage_counter_ref (tag, base);
189   tmp = force_reg (Pmode, XEXP (tmp, 0));
190   emit_move_insn (mr, tmp);
191
192   uval = gen_reg_rtx (value->hvalue.rtl.mode);
193   emit_move_insn (uval, copy_rtx (value->hvalue.rtl.value));
194
195   /* Check for non-power of 2.  */
196   if (value->hdata.pow2.may_be_other)
197     {
198       do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->hvalue.rtl.mode,
199                                NULL_RTX, NULL_RTX, end_of_code_label);
200       tmp = expand_simple_binop (value->hvalue.rtl.mode, PLUS, copy_rtx (uval),
201                                  constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN);
202       tmp = expand_simple_binop (value->hvalue.rtl.mode, AND, copy_rtx (uval), tmp,
203                                  NULL_RTX, 0, OPTAB_WIDEN);
204       do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->hvalue.rtl.mode, NULL_RTX,
205                                NULL_RTX, end_of_code_label);
206     }
207
208   /* Count log_2(value).  */
209   emit_label (loop_label);
210
211   tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter), mr, 0, OPTAB_WIDEN);
212   if (tmp != mr)
213     emit_move_insn (copy_rtx (mr), tmp);
214
215   tmp = expand_simple_binop (value->hvalue.rtl.mode, ASHIFTRT, copy_rtx (uval), const1_rtx,
216                              uval, 0, OPTAB_WIDEN);
217   if (tmp != uval)
218     emit_move_insn (copy_rtx (uval), tmp);
219
220   do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->hvalue.rtl.mode,
221                            NULL_RTX, NULL_RTX, loop_label);
222
223   /* Increase the counter.  */
224   emit_label (end_of_code_label);
225
226   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
227
228   tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
229                              mem_ref, 0, OPTAB_WIDEN);
230
231   if (tmp != mem_ref)
232     emit_move_insn (copy_rtx (mem_ref), tmp);
233
234   sequence = get_insns ();
235   end_sequence ();
236   rebuild_jump_labels (sequence);
237   safe_insert_insn_on_edge (sequence, e);
238 }
239
240 /* Output instructions as RTL for code to find the most common value.
241    VALUE is the expression whose value is profiled.  TAG is the tag of the
242    section for counters, BASE is offset of the counter position.  */
243
244 static rtx
245 rtl_gen_one_value_profiler_no_edge_manipulation (histogram_value value,
246                                                  unsigned tag, unsigned base)
247 {
248   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
249   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
250   rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all;
251   rtx tmp, uval;
252   rtx sequence;
253   rtx same_label = gen_label_rtx ();
254   rtx zero_label = gen_label_rtx ();
255   rtx end_of_code_label = gen_label_rtx ();
256
257   start_sequence ();
258
259   if (value->hvalue.rtl.seq)
260     emit_insn (value->hvalue.rtl.seq);
261
262   stored_value_ref = rtl_coverage_counter_ref (tag, base);
263   counter_ref = rtl_coverage_counter_ref (tag, base + 1);
264   all_ref = rtl_coverage_counter_ref (tag, base + 2);
265   stored_value = validize_mem (stored_value_ref);
266   counter = validize_mem (counter_ref);
267   all = validize_mem (all_ref);
268
269   uval = gen_reg_rtx (mode);
270   convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
271
272   /* Check if the stored value matches.  */
273   do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ,
274                            0, mode, NULL_RTX, NULL_RTX, same_label);
275
276   /* Does not match; check whether the counter is zero.  */
277   do_compare_rtx_and_jump (copy_rtx (counter), const0_rtx, EQ, 0, mode,
278                            NULL_RTX, NULL_RTX, zero_label);
279
280   /* The counter is not zero yet.  */
281   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx,
282                              counter, 0, OPTAB_WIDEN);
283
284   if (tmp != counter)
285     emit_move_insn (copy_rtx (counter), tmp);
286
287   emit_jump_insn (gen_jump (end_of_code_label));
288   emit_barrier ();
289
290   emit_label (zero_label);
291   /* Set new value.  */
292   emit_move_insn (copy_rtx (stored_value), copy_rtx (uval));
293
294   emit_label (same_label);
295   /* Increase the counter.  */
296   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), const1_rtx,
297                              counter, 0, OPTAB_WIDEN);
298
299   if (tmp != counter)
300     emit_move_insn (copy_rtx (counter), tmp);
301
302   emit_label (end_of_code_label);
303
304   /* Increase the counter of all executions; this seems redundant given
305      that ve have counts for edges in cfg, but it may happen that some
306      optimization will change the counts for the block (either because
307      it is unable to update them correctly, or because it will duplicate
308      the block or its part).  */
309   tmp = expand_simple_binop (mode, PLUS, copy_rtx (all), const1_rtx,
310                              all, 0, OPTAB_WIDEN);
311
312   if (tmp != all)
313     emit_move_insn (copy_rtx (all), tmp);
314   sequence = get_insns ();
315   end_sequence ();
316   return sequence;
317 }
318
319 /* Output instructions as RTL for code to find the most common value.
320    VALUE is the expression whose value is profiled.  TAG is the tag of the
321    section for counters, BASE is offset of the counter position.  */
322
323 static void
324 rtl_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
325 {
326   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
327                    PREV_INSN (value->hvalue.rtl.insn));
328   rtx sequence = rtl_gen_one_value_profiler_no_edge_manipulation (value, 
329                         tag, base);
330   rebuild_jump_labels (sequence);
331   safe_insert_insn_on_edge (sequence, e);
332 }
333
334 /* Output instructions as RTL for code to find the most common value of
335    a difference between two evaluations of an expression.
336    VALUE is the expression whose value is profiled.  TAG is the tag of the
337    section for counters, BASE is offset of the counter position.  */
338
339 static void
340 rtl_gen_const_delta_profiler (histogram_value value, unsigned tag, unsigned base)
341 {
342   histogram_value one_value_delta;
343   unsigned gcov_size = tree_low_cst (TYPE_SIZE (GCOV_TYPE_NODE), 1);
344   enum machine_mode mode = mode_for_size (gcov_size, MODE_INT, 0);
345   rtx stored_value_ref, stored_value, tmp, uval;
346   rtx sequence;
347   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
348                    PREV_INSN (value->hvalue.rtl.insn));
349
350   start_sequence ();
351
352   if (value->hvalue.rtl.seq)
353     emit_insn (value->hvalue.rtl.seq);
354
355   stored_value_ref = rtl_coverage_counter_ref (tag, base);
356   stored_value = validize_mem (stored_value_ref);
357
358   uval = gen_reg_rtx (mode);
359   convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
360   tmp = expand_simple_binop (mode, MINUS,
361                              copy_rtx (uval), copy_rtx (stored_value),
362                              NULL_RTX, 0, OPTAB_WIDEN);
363
364   one_value_delta = ggc_alloc (sizeof (*one_value_delta));
365   one_value_delta->hvalue.rtl.value = tmp;
366   one_value_delta->hvalue.rtl.mode = mode;
367   one_value_delta->hvalue.rtl.seq = NULL_RTX;
368   one_value_delta->hvalue.rtl.insn = value->hvalue.rtl.insn;
369   one_value_delta->type = HIST_TYPE_SINGLE_VALUE;
370   emit_insn (rtl_gen_one_value_profiler_no_edge_manipulation (one_value_delta,
371                                                               tag, base + 1));
372   emit_move_insn (copy_rtx (stored_value), uval);
373   sequence = get_insns ();
374   end_sequence ();
375   rebuild_jump_labels (sequence);
376   safe_insert_insn_on_edge (sequence, e);
377 }
378
379 /* Return the file on which profile dump output goes, if any.  */
380
381 static FILE *rtl_profile_dump_file (void) {
382   return dump_file;
383 }
384 \f
385 struct profile_hooks rtl_profile_hooks =
386 {
387   rtl_init_edge_profiler,
388   rtl_gen_edge_profiler,
389   rtl_gen_interval_profiler,
390   rtl_gen_pow2_profiler,
391   rtl_gen_one_value_profiler,
392   rtl_gen_const_delta_profiler,
393   rtl_profile_dump_file
394 };