]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/profile-count.h
1 /* Profile counter container type.
2 Copyright (C) 2017 Free Software Foundation, Inc.
3 Contributed by Jan Hubicka
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_PROFILE_COUNT_H
22 #define GCC_PROFILE_COUNT_H
25 /* The base value for branch probability notes and edge probabilities. */
26 #define REG_BR_PROB_BASE 10000
28 #define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
30 /* Main data type to hold profile counters in GCC. In most cases profile
31 counts originate from profile feedback. They are 64bit integers
32 representing number of executions during the train run.
33 As the profile is maintained during the compilation, many adjustments are
34 made. Not all transformations can be made precisely, most importantly
35 when code is being duplicated. It also may happen that part of CFG has
36 profile counts known while other do not - for example when LTO optimizing
37 partly profiled program or when profile was lost due to COMDAT merging.
39 For this information profile_count tracks more information than
40 just unsigned integer and it is also ready for profile mismatches.
41 The API of this data type represent operations that are natural
42 on profile counts - sum, difference and operation with scales and
43 probabilities. All operations are safe by never getting negative counts
44 and they do end up in uninitialized scale if any of the parameters is
47 All comparsions that are three state and handling of probabilities. Thus
48 a < b is not equal to !(a >= b).
50 The following pre-defined counts are available:
52 profile_count::zero () for code that is known to execute zero times at
53 runtime (this can be detected statically i.e. for paths leading to
55 profile_count::one () for code that is known to execute once (such as
57 profile_count::uninitialized () for unknown execution count.
62 class GTY(()) profile_count
64 /* Use int64_t to hold basic block counters. Should be at least
65 64bit. Although a counter cannot be negative, we use a signed
66 type to hold various extra stages. */
70 /* Assume numbers smaller than this to multiply. This is set to make
71 testsuite pass, in future we may implement precise multiples in higer
73 static const int64_t max_safe_multiplier
= 131072;
76 /* Used for counters which are expected to be never executed. */
77 static profile_count
zero ()
79 return from_gcov_type (0);
81 static profile_count
one ()
83 return from_gcov_type (1);
85 /* Value of counters which has not been initialized. Either because
86 initialization did not happen yet or because profile is unknown. */
87 static profile_count
uninitialized ()
94 /* The profiling runtime uses gcov_type, which is usually 64bit integer.
95 Conversions back and forth are used to read the coverage and get it
96 into internal representation. */
97 static profile_count
from_gcov_type (gcov_type v
)
100 gcc_checking_assert (v
>=0);
105 /* Conversion to gcov_type is lossy. */
106 gcov_type
to_gcov_type () const
108 gcc_checking_assert (initialized_p ());
112 /* Return true if value has been initialized. */
113 bool initialized_p () const
117 /* Return true if value can be trusted. */
118 bool reliable_p () const
120 return initialized_p ();
123 /* Basic operations. */
124 bool operator== (const profile_count
&other
) const
126 return m_val
== other
.m_val
;
128 profile_count
operator+ (const profile_count
&other
) const
130 if (other
== profile_count::zero ())
132 if (*this == profile_count::zero ())
134 if (!initialized_p () || !other
.initialized_p ())
135 return profile_count::uninitialized ();
138 ret
.m_val
= m_val
+ other
.m_val
;
141 profile_count
&operator+= (const profile_count
&other
)
143 if (other
== profile_count::zero ())
145 if (*this == profile_count::zero ())
150 if (!initialized_p () || !other
.initialized_p ())
151 return *this = profile_count::uninitialized ();
153 m_val
+= other
.m_val
;
156 profile_count
operator- (const profile_count
&other
) const
158 if (*this == profile_count::zero () || other
== profile_count::zero ())
160 if (!initialized_p () || !other
.initialized_p ())
161 return profile_count::uninitialized ();
163 ret
.m_val
= MAX (m_val
- other
.m_val
, 0);
166 profile_count
&operator-= (const profile_count
&other
)
168 if (*this == profile_count::zero () || other
== profile_count::zero ())
170 if (!initialized_p () || !other
.initialized_p ())
171 return *this = profile_count::uninitialized ();
173 m_val
= MAX (m_val
- other
.m_val
, 0);
177 /* Return false if profile_count is bogus. */
183 /* Comparsions are three-state and conservative. False is returned if
184 the inequality can not be decided. */
185 bool operator< (const profile_count
&other
) const
187 return initialized_p () && other
.initialized_p () && m_val
< other
.m_val
;
189 bool operator> (const profile_count
&other
) const
191 return initialized_p () && other
.initialized_p () && m_val
> other
.m_val
;
193 bool operator< (const gcov_type other
) const
195 return initialized_p () && m_val
< other
;
197 bool operator> (const gcov_type other
) const
199 return initialized_p () && m_val
> other
;
202 bool operator<= (const profile_count
&other
) const
204 return initialized_p () && other
.initialized_p () && m_val
<= other
.m_val
;
206 bool operator>= (const profile_count
&other
) const
208 return initialized_p () && m_val
>= other
.m_val
;
210 bool operator<= (const gcov_type other
) const
212 return initialized_p () && m_val
<= other
;
214 bool operator>= (const gcov_type other
) const
216 return initialized_p () && m_val
>= other
;
219 /* PROB is a probability in scale 0...REG_BR_PROB_BASE. Scale counter
221 profile_count
apply_probability (int prob
) const
223 gcc_checking_assert (prob
>= 0 && prob
<= REG_BR_PROB_BASE
);
224 if (!initialized_p ())
225 return profile_count::uninitialized ();
227 ret
.m_val
= RDIV (m_val
* prob
, REG_BR_PROB_BASE
);
230 /* Return *THIS * NUM / DEN. */
231 profile_count
apply_scale (int64_t num
, int64_t den
) const
233 if (!initialized_p ())
234 return profile_count::uninitialized ();
236 /* FIXME: shrink wrapping violates this sanity check. */
237 gcc_checking_assert ((num
>= 0
238 && (num
<= REG_BR_PROB_BASE
239 || den
<= REG_BR_PROB_BASE
)
241 ret
.m_val
= RDIV (m_val
* num
, den
);
244 profile_count
apply_scale (profile_count num
, profile_count den
) const
246 if (*this == profile_count::zero ())
247 return profile_count::zero ();
248 if (!initialized_p () || !num
.initialized_p () || !den
.initialized_p ())
249 return profile_count::uninitialized ();
251 gcc_checking_assert (den
> 0);
252 /* Take care for overflows! */
253 if (num
.m_val
< max_safe_multiplier
|| m_val
< max_safe_multiplier
)
254 ret
.m_val
= RDIV (m_val
* num
.m_val
, den
.m_val
);
256 ret
.m_val
= RDIV (m_val
* RDIV (num
.m_val
* max_safe_multiplier
,
257 den
.m_val
), max_safe_multiplier
);
261 /* Return probability of event with counter THIS within event with counter
263 int probability_in (profile_count overall
)
265 if (*this == profile_count::zero ())
267 if (!initialized_p () || !overall
.initialized_p ())
268 return REG_BR_PROB_BASE
/ 2;
270 return REG_BR_PROB_BASE
;
272 return REG_BR_PROB_BASE
/ 2;
273 return RDIV (m_val
* REG_BR_PROB_BASE
, overall
.m_val
);
276 /* Output THIS to F. */
277 void dump (FILE *f
) const;
279 /* Print THIS to stderr. */
282 /* Return true if THIS is known to differ significantly from OTHER. */
283 bool differs_from_p (profile_count other
) const;
285 /* LTO streaming support. */
286 static profile_count
stream_in (struct lto_input_block
*);
287 void stream_out (struct output_block
*);
288 void stream_out (struct lto_output_stream
*);