OSDN Git Service

2005-04-12 Aaron Luchko <aluchko@redhat.com>
[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   enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
87   rtx mem_ref, tmp, tmp1, mr, val;
88   rtx sequence;
89   rtx more_label = gen_label_rtx ();
90   rtx less_label = gen_label_rtx ();
91   rtx end_of_code_label = gen_label_rtx ();
92   int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
93   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
94                    PREV_INSN (value->hvalue.rtl.insn));
95
96   start_sequence ();
97
98   if (value->hvalue.rtl.seq)
99     emit_insn (value->hvalue.rtl.seq);
100
101   mr = gen_reg_rtx (Pmode);
102
103   tmp = rtl_coverage_counter_ref (tag, base);
104   tmp = force_reg (Pmode, XEXP (tmp, 0));
105
106   val = expand_simple_binop (value->hvalue.rtl.mode, MINUS,
107                              copy_rtx (value->hvalue.rtl.value),
108                              GEN_INT (value->hdata.intvl.int_start),
109                              NULL_RTX, 0, OPTAB_WIDEN);
110
111     do_compare_rtx_and_jump (copy_rtx (val), GEN_INT (value->hdata.intvl.steps),
112                            GE, 0, value->hvalue.rtl.mode, NULL_RTX, NULL_RTX, 
113                            more_label);
114   do_compare_rtx_and_jump (copy_rtx (val), const0_rtx, LT, 0, 
115                            value->hvalue.rtl.mode,
116                              NULL_RTX, NULL_RTX, less_label);
117
118   /* We are in range.  */
119   tmp1 = expand_simple_binop (value->hvalue.rtl.mode, MULT,
120                               copy_rtx (val), GEN_INT (per_counter),
121                               NULL_RTX, 0, OPTAB_WIDEN);
122   tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp), tmp1, mr,
123                               0, OPTAB_WIDEN);
124   if (tmp1 != mr)
125     emit_move_insn (copy_rtx (mr), tmp1);
126
127       emit_jump_insn (gen_jump (end_of_code_label));
128       emit_barrier ();
129
130   /* Above the interval.  */
131       emit_label (more_label);
132       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
133                                   GEN_INT (per_counter * value->hdata.intvl.steps),
134                                   mr, 0, OPTAB_WIDEN);
135       if (tmp1 != mr)
136         emit_move_insn (copy_rtx (mr), tmp1);
137           emit_jump_insn (gen_jump (end_of_code_label));
138           emit_barrier ();
139
140   /* Below the interval.  */
141       emit_label (less_label);
142       tmp1 = expand_simple_binop (Pmode, PLUS, copy_rtx (tmp),
143                         GEN_INT (per_counter * (value->hdata.intvl.steps +1)),
144                 mr, 0, OPTAB_WIDEN);
145       if (tmp1 != mr)
146         emit_move_insn (copy_rtx (mr), tmp1);
147
148     emit_label (end_of_code_label);
149
150   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
151
152   tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
153                              mem_ref, 0, OPTAB_WIDEN);
154
155   if (tmp != mem_ref)
156     emit_move_insn (copy_rtx (mem_ref), tmp);
157
158   sequence = get_insns ();
159   end_sequence ();
160   rebuild_jump_labels (sequence);
161   safe_insert_insn_on_edge (sequence, e);
162 }
163
164 /* Output instructions as RTL to increment the power of two histogram counter.
165    VALUE is the expression whose value is profiled.  TAG is the tag of the
166    section for counters, BASE is offset of the counter position.  */
167
168 static void
169 rtl_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
170 {
171   enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
172   rtx mem_ref, tmp, mr, uval;
173   rtx sequence;
174   rtx end_of_code_label = gen_label_rtx ();
175   rtx loop_label = gen_label_rtx ();
176   int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
177   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
178                    PREV_INSN (value->hvalue.rtl.insn));
179
180   start_sequence ();
181
182   if (value->hvalue.rtl.seq)
183     emit_insn (value->hvalue.rtl.seq);
184
185   mr = gen_reg_rtx (Pmode);
186   tmp = rtl_coverage_counter_ref (tag, base);
187   tmp = force_reg (Pmode, XEXP (tmp, 0));
188   emit_move_insn (mr, tmp);
189
190   uval = gen_reg_rtx (value->hvalue.rtl.mode);
191   emit_move_insn (uval, copy_rtx (value->hvalue.rtl.value));
192
193   /* Check for non-power of 2.  */
194   if (value->hdata.pow2.may_be_other)
195     {
196       do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->hvalue.rtl.mode,
197                                NULL_RTX, NULL_RTX, end_of_code_label);
198       tmp = expand_simple_binop (value->hvalue.rtl.mode, PLUS, copy_rtx (uval),
199                                  constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN);
200       tmp = expand_simple_binop (value->hvalue.rtl.mode, AND, copy_rtx (uval), tmp,
201                                  NULL_RTX, 0, OPTAB_WIDEN);
202       do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->hvalue.rtl.mode, NULL_RTX,
203                                NULL_RTX, end_of_code_label);
204     }
205
206   /* Count log_2(value).  */
207   emit_label (loop_label);
208
209   tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter), mr, 0, OPTAB_WIDEN);
210   if (tmp != mr)
211     emit_move_insn (copy_rtx (mr), tmp);
212
213   tmp = expand_simple_binop (value->hvalue.rtl.mode, ASHIFTRT, copy_rtx (uval), const1_rtx,
214                              uval, 0, OPTAB_WIDEN);
215   if (tmp != uval)
216     emit_move_insn (copy_rtx (uval), tmp);
217
218   do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->hvalue.rtl.mode,
219                            NULL_RTX, NULL_RTX, loop_label);
220
221   /* Increase the counter.  */
222   emit_label (end_of_code_label);
223
224   mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
225
226   tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
227                              mem_ref, 0, OPTAB_WIDEN);
228
229   if (tmp != mem_ref)
230     emit_move_insn (copy_rtx (mem_ref), tmp);
231
232   sequence = get_insns ();
233   end_sequence ();
234   rebuild_jump_labels (sequence);
235   safe_insert_insn_on_edge (sequence, e);
236 }
237
238 /* Output instructions as RTL for code to find the most common value.
239    VALUE is the expression whose value is profiled.  TAG is the tag of the
240    section for counters, BASE is offset of the counter position.  */
241
242 static rtx
243 rtl_gen_one_value_profiler_no_edge_manipulation (histogram_value value,
244                                                  unsigned tag, unsigned base)
245 {
246   enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
247   rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all;
248   rtx tmp, uval;
249   rtx sequence;
250   rtx same_label = gen_label_rtx ();
251   rtx zero_label = gen_label_rtx ();
252   rtx end_of_code_label = gen_label_rtx ();
253
254   start_sequence ();
255
256   if (value->hvalue.rtl.seq)
257     emit_insn (value->hvalue.rtl.seq);
258
259   stored_value_ref = rtl_coverage_counter_ref (tag, base);
260   counter_ref = rtl_coverage_counter_ref (tag, base + 1);
261   all_ref = rtl_coverage_counter_ref (tag, base + 2);
262   stored_value = validize_mem (stored_value_ref);
263   counter = validize_mem (counter_ref);
264   all = validize_mem (all_ref);
265
266   uval = gen_reg_rtx (mode);
267   convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
268
269   /* Check if the stored value matches.  */
270   do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ,
271                            0, mode, NULL_RTX, NULL_RTX, same_label);
272
273   /* Does not match; check whether the counter is zero.  */
274   do_compare_rtx_and_jump (copy_rtx (counter), const0_rtx, EQ, 0, mode,
275                            NULL_RTX, NULL_RTX, zero_label);
276
277   /* The counter is not zero yet.  */
278   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx,
279                              counter, 0, OPTAB_WIDEN);
280
281   if (tmp != counter)
282     emit_move_insn (copy_rtx (counter), tmp);
283
284   emit_jump_insn (gen_jump (end_of_code_label));
285   emit_barrier ();
286
287   emit_label (zero_label);
288   /* Set new value.  */
289   emit_move_insn (copy_rtx (stored_value), copy_rtx (uval));
290
291   emit_label (same_label);
292   /* Increase the counter.  */
293   tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), const1_rtx,
294                              counter, 0, OPTAB_WIDEN);
295
296   if (tmp != counter)
297     emit_move_insn (copy_rtx (counter), tmp);
298
299   emit_label (end_of_code_label);
300
301   /* Increase the counter of all executions; this seems redundant given
302      that ve have counts for edges in cfg, but it may happen that some
303      optimization will change the counts for the block (either because
304      it is unable to update them correctly, or because it will duplicate
305      the block or its part).  */
306   tmp = expand_simple_binop (mode, PLUS, copy_rtx (all), const1_rtx,
307                              all, 0, OPTAB_WIDEN);
308
309   if (tmp != all)
310     emit_move_insn (copy_rtx (all), tmp);
311   sequence = get_insns ();
312   end_sequence ();
313   return sequence;
314 }
315
316 /* Output instructions as RTL for code to find the most common value.
317    VALUE is the expression whose value is profiled.  TAG is the tag of the
318    section for counters, BASE is offset of the counter position.  */
319
320 static void
321 rtl_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
322 {
323   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
324                    PREV_INSN (value->hvalue.rtl.insn));
325   rtx sequence = rtl_gen_one_value_profiler_no_edge_manipulation (value, 
326                         tag, base);
327   rebuild_jump_labels (sequence);
328   safe_insert_insn_on_edge (sequence, e);
329 }
330
331 /* Output instructions as RTL for code to find the most common value of
332    a difference between two evaluations of an expression.
333    VALUE is the expression whose value is profiled.  TAG is the tag of the
334    section for counters, BASE is offset of the counter position.  */
335
336 static void
337 rtl_gen_const_delta_profiler (histogram_value value, unsigned tag, unsigned base)
338 {
339   histogram_value one_value_delta;
340   enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
341   rtx stored_value_ref, stored_value, tmp, uval;
342   rtx sequence;
343   edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
344                    PREV_INSN (value->hvalue.rtl.insn));
345
346   start_sequence ();
347
348   if (value->hvalue.rtl.seq)
349     emit_insn (value->hvalue.rtl.seq);
350
351   stored_value_ref = rtl_coverage_counter_ref (tag, base);
352   stored_value = validize_mem (stored_value_ref);
353
354   uval = gen_reg_rtx (mode);
355   convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
356   tmp = expand_simple_binop (mode, MINUS,
357                              copy_rtx (uval), copy_rtx (stored_value),
358                              NULL_RTX, 0, OPTAB_WIDEN);
359
360   one_value_delta = ggc_alloc (sizeof (*one_value_delta));
361   one_value_delta->hvalue.rtl.value = tmp;
362   one_value_delta->hvalue.rtl.mode = mode;
363   one_value_delta->hvalue.rtl.seq = NULL_RTX;
364   one_value_delta->hvalue.rtl.insn = value->hvalue.rtl.insn;
365   one_value_delta->type = HIST_TYPE_SINGLE_VALUE;
366   emit_insn (rtl_gen_one_value_profiler_no_edge_manipulation (one_value_delta,
367                                                               tag, base + 1));
368   emit_move_insn (copy_rtx (stored_value), uval);
369   sequence = get_insns ();
370   end_sequence ();
371   rebuild_jump_labels (sequence);
372   safe_insert_insn_on_edge (sequence, e);
373 }
374
375 /* Return the file on which profile dump output goes, if any.  */
376
377 static FILE *rtl_profile_dump_file (void) {
378   return dump_file;
379 }
380 \f
381 struct profile_hooks rtl_profile_hooks =
382 {
383   rtl_init_edge_profiler,
384   rtl_gen_edge_profiler,
385   rtl_gen_interval_profiler,
386   rtl_gen_pow2_profiler,
387   rtl_gen_one_value_profiler,
388   rtl_gen_const_delta_profiler,
389   rtl_profile_dump_file
390 };