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, 51 Franklin Street, Fifth Floor, Boston, MA
23 02110-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 
46 static void
rtl_init_edge_profiler(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
rtl_gen_edge_profiler(int edgeno,edge e)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
rtl_gen_interval_profiler(histogram_value value,unsigned tag,unsigned base)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
rtl_gen_pow2_profiler(histogram_value value,unsigned tag,unsigned base)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   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 
228 static rtx
rtl_gen_one_value_profiler_no_edge_manipulation(histogram_value value,unsigned tag,unsigned base)229 rtl_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 
306 static void
rtl_gen_one_value_profiler(histogram_value value,unsigned tag,unsigned base)307 rtl_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 
322 static void
rtl_gen_const_delta_profiler(histogram_value value,unsigned tag,unsigned base)323 rtl_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 
rtl_profile_dump_file(void)363 static FILE *rtl_profile_dump_file (void) {
364   return dump_file;
365 }
366 
367 struct 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