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
8This file is part of GCC.
9
10GCC is free software; you can redistribute it and/or modify it under
11the terms of the GNU General Public License as published by the Free
12Software Foundation; either version 2, or (at your option) any later
13version.
14
15GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18for more details.
19
20You should have received a copy of the GNU General Public License
21along with GCC; see the file COPYING.  If not, write to the Free
22Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2302110-1301, 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
46static void
47rtl_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
56static void
57rtl_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
83static void
84rtl_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
168static void
169rtl_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  int per_counter = GCOV_TYPE_SIZE / BITS_PER_UNIT;
176  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
177			PREV_INSN (value->hvalue.rtl.insn));
178
179  start_sequence ();
180
181  if (value->hvalue.rtl.seq)
182    emit_insn (value->hvalue.rtl.seq);
183
184  mr = gen_reg_rtx (Pmode);
185  tmp = rtl_coverage_counter_ref (tag, base);
186  tmp = force_reg (Pmode, XEXP (tmp, 0));
187  emit_move_insn (mr, tmp);
188
189  uval = gen_reg_rtx (value->hvalue.rtl.mode);
190  emit_move_insn (uval, copy_rtx (value->hvalue.rtl.value));
191
192  /* Check for non-power of 2.  */
193  do_compare_rtx_and_jump (copy_rtx (uval), const0_rtx, LE, 0, value->hvalue.rtl.mode,
194			   NULL_RTX, NULL_RTX, end_of_code_label);
195  tmp = expand_simple_binop (value->hvalue.rtl.mode, PLUS, copy_rtx (uval),
196			     constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN);
197  tmp = expand_simple_binop (value->hvalue.rtl.mode, AND, copy_rtx (uval), tmp,
198			     NULL_RTX, 0, OPTAB_WIDEN);
199  do_compare_rtx_and_jump (tmp, const0_rtx, NE, 0, value->hvalue.rtl.mode, NULL_RTX,
200			   NULL_RTX, end_of_code_label);
201
202  tmp = expand_simple_binop (Pmode, PLUS, copy_rtx (mr), GEN_INT (per_counter),
203			     mr, 0, OPTAB_WIDEN);
204  if (tmp != mr)
205    emit_move_insn (copy_rtx (mr), tmp);
206
207  /* Increase the counter.  */
208  emit_label (end_of_code_label);
209
210  mem_ref = validize_mem (gen_rtx_MEM (mode, mr));
211
212  tmp = expand_simple_binop (mode, PLUS, copy_rtx (mem_ref), const1_rtx,
213			     mem_ref, 0, OPTAB_WIDEN);
214
215  if (tmp != mem_ref)
216    emit_move_insn (copy_rtx (mem_ref), tmp);
217
218  sequence = get_insns ();
219  end_sequence ();
220  rebuild_jump_labels (sequence);
221  safe_insert_insn_on_edge (sequence, e);
222}
223
224/* Output instructions as RTL for code to find the most common value.
225   VALUE is the expression whose value is profiled.  TAG is the tag of the
226   section for counters, BASE is offset of the counter position.  */
227
228static rtx
229rtl_gen_one_value_profiler_no_edge_manipulation (histogram_value value,
230						 unsigned tag, unsigned base)
231{
232  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
233  rtx stored_value_ref, counter_ref, all_ref, stored_value, counter, all;
234  rtx tmp, uval;
235  rtx sequence;
236  rtx same_label = gen_label_rtx ();
237  rtx zero_label = gen_label_rtx ();
238  rtx end_of_code_label = gen_label_rtx ();
239
240  start_sequence ();
241
242  if (value->hvalue.rtl.seq)
243    emit_insn (value->hvalue.rtl.seq);
244
245  stored_value_ref = rtl_coverage_counter_ref (tag, base);
246  counter_ref = rtl_coverage_counter_ref (tag, base + 1);
247  all_ref = rtl_coverage_counter_ref (tag, base + 2);
248  stored_value = validize_mem (stored_value_ref);
249  counter = validize_mem (counter_ref);
250  all = validize_mem (all_ref);
251
252  uval = gen_reg_rtx (mode);
253  convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
254
255  /* Check if the stored value matches.  */
256  do_compare_rtx_and_jump (copy_rtx (uval), copy_rtx (stored_value), EQ,
257			   0, mode, NULL_RTX, NULL_RTX, same_label);
258
259  /* Does not match; check whether the counter is zero.  */
260  do_compare_rtx_and_jump (copy_rtx (counter), const0_rtx, EQ, 0, mode,
261			   NULL_RTX, NULL_RTX, zero_label);
262
263  /* The counter is not zero yet.  */
264  tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), constm1_rtx,
265			     counter, 0, OPTAB_WIDEN);
266
267  if (tmp != counter)
268    emit_move_insn (copy_rtx (counter), tmp);
269
270  emit_jump_insn (gen_jump (end_of_code_label));
271  emit_barrier ();
272
273  emit_label (zero_label);
274  /* Set new value.  */
275  emit_move_insn (copy_rtx (stored_value), copy_rtx (uval));
276
277  emit_label (same_label);
278  /* Increase the counter.  */
279  tmp = expand_simple_binop (mode, PLUS, copy_rtx (counter), const1_rtx,
280			     counter, 0, OPTAB_WIDEN);
281
282  if (tmp != counter)
283    emit_move_insn (copy_rtx (counter), tmp);
284
285  emit_label (end_of_code_label);
286
287  /* Increase the counter of all executions; this seems redundant given
288     that ve have counts for edges in cfg, but it may happen that some
289     optimization will change the counts for the block (either because
290     it is unable to update them correctly, or because it will duplicate
291     the block or its part).  */
292  tmp = expand_simple_binop (mode, PLUS, copy_rtx (all), const1_rtx,
293			     all, 0, OPTAB_WIDEN);
294
295  if (tmp != all)
296    emit_move_insn (copy_rtx (all), tmp);
297  sequence = get_insns ();
298  end_sequence ();
299  return sequence;
300}
301
302/* Output instructions as RTL for code to find the most common value.
303   VALUE is the expression whose value is profiled.  TAG is the tag of the
304   section for counters, BASE is offset of the counter position.  */
305
306static void
307rtl_gen_one_value_profiler (histogram_value value, unsigned tag, unsigned base)
308{
309  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
310		   PREV_INSN (value->hvalue.rtl.insn));
311  rtx sequence = rtl_gen_one_value_profiler_no_edge_manipulation (value,
312			tag, base);
313  rebuild_jump_labels (sequence);
314  safe_insert_insn_on_edge (sequence, e);
315}
316
317/* Output instructions as RTL for code to find the most common value of
318   a difference between two evaluations of an expression.
319   VALUE is the expression whose value is profiled.  TAG is the tag of the
320   section for counters, BASE is offset of the counter position.  */
321
322static void
323rtl_gen_const_delta_profiler (histogram_value value, unsigned tag, unsigned base)
324{
325  histogram_value one_value_delta;
326  enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
327  rtx stored_value_ref, stored_value, tmp, uval;
328  rtx sequence;
329  edge e = split_block (BLOCK_FOR_INSN (value->hvalue.rtl.insn),
330		   PREV_INSN (value->hvalue.rtl.insn));
331
332  start_sequence ();
333
334  if (value->hvalue.rtl.seq)
335    emit_insn (value->hvalue.rtl.seq);
336
337  stored_value_ref = rtl_coverage_counter_ref (tag, base);
338  stored_value = validize_mem (stored_value_ref);
339
340  uval = gen_reg_rtx (mode);
341  convert_move (uval, copy_rtx (value->hvalue.rtl.value), 0);
342  tmp = expand_simple_binop (mode, MINUS,
343			     copy_rtx (uval), copy_rtx (stored_value),
344			     NULL_RTX, 0, OPTAB_WIDEN);
345
346  one_value_delta = ggc_alloc (sizeof (*one_value_delta));
347  one_value_delta->hvalue.rtl.value = tmp;
348  one_value_delta->hvalue.rtl.mode = mode;
349  one_value_delta->hvalue.rtl.seq = NULL_RTX;
350  one_value_delta->hvalue.rtl.insn = value->hvalue.rtl.insn;
351  one_value_delta->type = HIST_TYPE_SINGLE_VALUE;
352  emit_insn (rtl_gen_one_value_profiler_no_edge_manipulation (one_value_delta,
353							      tag, base + 1));
354  emit_move_insn (copy_rtx (stored_value), uval);
355  sequence = get_insns ();
356  end_sequence ();
357  rebuild_jump_labels (sequence);
358  safe_insert_insn_on_edge (sequence, e);
359}
360
361/* Return the file on which profile dump output goes, if any.  */
362
363static FILE *rtl_profile_dump_file (void) {
364  return dump_file;
365}
366
367struct profile_hooks rtl_profile_hooks =
368{
369  rtl_init_edge_profiler,
370  rtl_gen_edge_profiler,
371  rtl_gen_interval_profiler,
372  rtl_gen_pow2_profiler,
373  rtl_gen_one_value_profiler,
374  rtl_gen_const_delta_profiler,
375  rtl_profile_dump_file
376};
377