* varasm.c (assemble_start_function): Remove reset of in_section.
[official-gcc.git] / gcc / rtl-profile.c
blob614525d44fec0c2312f004aca275f4d9d56b12b6
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.
8 This file is part of GCC.
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.
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.
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. */
25 /* Generate basic block profile instrumentation and auxiliary files.
26 RTL-based version. See profile.c for overview. */
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"
44 /* Do initialization work for the edge profiler. */
46 static void
47 rtl_init_edge_profiler (void)
49 /* gen_edge_profiler calls safe_insert_insn_on_edge which needs
50 register liveness data to be available. */
51 life_analysis (NULL, 0);
54 /* Output instructions as RTL to increment the edge execution count. */
56 static void
57 rtl_gen_edge_profiler (int edgeno, edge e)
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;
64 start_sequence ();
65 ref = validize_mem (ref);
67 tmp = expand_simple_binop (mode, PLUS, ref, const1_rtx,
68 ref, 0, OPTAB_WIDEN);
70 if (tmp != ref)
71 emit_move_insn (copy_rtx (ref), tmp);
73 sequence = get_insns ();
74 end_sequence ();
75 safe_insert_insn_on_edge (sequence, e);
76 rebuild_jump_labels (e->insns.r);
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. */
83 static void
84 rtl_gen_interval_profiler (histogram_value value, unsigned tag, unsigned base)
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));
96 start_sequence ();
98 if (value->hvalue.rtl.seq)
99 emit_insn (value->hvalue.rtl.seq);
101 mr = gen_reg_rtx (Pmode);
103 tmp = rtl_coverage_counter_ref (tag, base);
104 tmp = force_reg (Pmode, XEXP (tmp, 0));
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);
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);
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);
127 emit_jump_insn (gen_jump (end_of_code_label));
128 emit_barrier ();
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 ();
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);
148 emit_label (end_of_code_label);
150 mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
152 tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
153 mem_ref, 0, OPTAB_WIDEN);
155 if (tmp != mem_ref)
156 emit_move_insn (copy_rtx (mem_ref), tmp);
158 sequence = get_insns ();
159 end_sequence ();
160 rebuild_jump_labels (sequence);
161 safe_insert_insn_on_edge (sequence, e);
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. */
168 static void
169 rtl_gen_pow2_profiler (histogram_value value, unsigned tag, unsigned base)
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));
180 start_sequence ();
182 if (value->hvalue.rtl.seq)
183 emit_insn (value->hvalue.rtl.seq);
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);
190 uval = gen_reg_rtx (value->hvalue.rtl.mode);
191 emit_move_insn (uval, copy_rtx (value->hvalue.rtl.value));
193 /* Check for non-power of 2. */
194 if (value->hdata.pow2.may_be_other)
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);
206 /* Count log_2(value). */
207 emit_label (loop_label);
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);
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);
218 do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, NE, 0, value->hvalue.rtl.mode,
219 NULL_RTX, NULL_RTX, loop_label);
221 /* Increase the counter. */
222 emit_label (end_of_code_label);
224 mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
226 tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
227 mem_ref, 0, OPTAB_WIDEN);
229 if (tmp != mem_ref)
230 emit_move_insn (copy_rtx (mem_ref), tmp);
232 sequence = get_insns ();
233 end_sequence ();
234 rebuild_jump_labels (sequence);
235 safe_insert_insn_on_edge (sequence, e);
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. */
242 static rtx
243 rtl_gen_one_value_profiler_no_edge_manipulation (histogram_value value,
244 unsigned tag, unsigned base)
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 ();
254 start_sequence ();
256 if (value->hvalue.rtl.seq)
257 emit_insn (value->hvalue.rtl.seq);
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);
266 uval = gen_reg_rtx (mode);
267 convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
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);
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);
277 /* The counter is not zero yet. */
278 tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx,
279 counter, 0, OPTAB_WIDEN);
281 if (tmp != counter)
282 emit_move_insn (copy_rtx (counter), tmp);
284 emit_jump_insn (gen_jump (end_of_code_label));
285 emit_barrier ();
287 emit_label (zero_label);
288 /* Set new value. */
289 emit_move_insn (copy_rtx (stored_value), copy_rtx (uval));
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);
296 if (tmp != counter)
297 emit_move_insn (copy_rtx (counter), tmp);
299 emit_label (end_of_code_label);
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);
309 if (tmp != all)
310 emit_move_insn (copy_rtx (all), tmp);
311 sequence = get_insns ();
312 end_sequence ();
313 return sequence;
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. */
320 static void
321 rtl_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
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);
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. */
336 static void
337 rtl_gen_const_delta_profiler (histogram_value value, unsigned tag, unsigned base)
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));
346 start_sequence ();
348 if (value->hvalue.rtl.seq)
349 emit_insn (value->hvalue.rtl.seq);
351 stored_value_ref = rtl_coverage_counter_ref (tag, base);
352 stored_value = validize_mem (stored_value_ref);
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);
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);
375 /* Return the file on which profile dump output goes, if any. */
377 static FILE *rtl_profile_dump_file (void) {
378 return dump_file;
381 struct profile_hooks rtl_profile_hooks =
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