re PR c++/24780 (ICE set_mem_attributes_minus_bitpos)
[gcc.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, 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
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 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
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
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
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
363 static FILE *rtl_profile_dump_file (void) {
364 return dump_file;
365 }
366 \f
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 };