1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2024 Free Software Foundation, Inc.
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 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
27 #if !defined(inhibit_libc)
29 #ifdef L_gcov_interval_profiler
30 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
31 corresponding counter in COUNTERS. If the VALUE is above or below
32 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
36 __gcov_interval_profiler (gcov_type
*counters
, gcov_type value
,
37 int start
, unsigned steps
)
39 gcov_type delta
= value
- start
;
41 counters
[steps
+ 1]++;
42 else if (delta
>= steps
)
49 #if defined(L_gcov_interval_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
50 /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
51 corresponding counter in COUNTERS. If the VALUE is above or below
52 the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
53 instead. Function is thread-safe. */
56 __gcov_interval_profiler_atomic (gcov_type
*counters
, gcov_type value
,
57 int start
, unsigned steps
)
59 gcov_type delta
= value
- start
;
61 __atomic_fetch_add (&counters
[steps
+ 1], 1, __ATOMIC_RELAXED
);
62 else if (delta
>= steps
)
63 __atomic_fetch_add (&counters
[steps
], 1, __ATOMIC_RELAXED
);
65 __atomic_fetch_add (&counters
[delta
], 1, __ATOMIC_RELAXED
);
69 #ifdef L_gcov_pow2_profiler
70 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
71 COUNTERS[0] is incremented. */
74 __gcov_pow2_profiler (gcov_type
*counters
, gcov_type value
)
76 if (value
== 0 || (value
& (value
- 1)))
83 #if defined(L_gcov_pow2_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
84 /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
85 COUNTERS[0] is incremented. Function is thread-safe. */
88 __gcov_pow2_profiler_atomic (gcov_type
*counters
, gcov_type value
)
90 if (value
== 0 || (value
& (value
- 1)))
91 __atomic_fetch_add (&counters
[0], 1, __ATOMIC_RELAXED
);
93 __atomic_fetch_add (&counters
[1], 1, __ATOMIC_RELAXED
);
97 /* Tries to determine N most commons value among its inputs. */
100 __gcov_topn_values_profiler_body (gcov_type
*counters
, gcov_type value
,
103 gcov_topn_add_value (counters
, value
, 1, use_atomic
, 1);
106 #ifdef L_gcov_topn_values_profiler
108 __gcov_topn_values_profiler (gcov_type
*counters
, gcov_type value
)
110 __gcov_topn_values_profiler_body (counters
, value
, 0);
114 #if defined(L_gcov_topn_values_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
116 /* Update one value profilers (COUNTERS) for a given VALUE.
118 CAVEAT: Following function is not thread-safe, only total number
119 of executions (COUNTERS[2]) is update with an atomic instruction.
120 Problem is that one cannot atomically update two counters
121 (COUNTERS[0] and COUNTERS[1]), for more information please read
122 following email thread:
123 https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */
126 __gcov_topn_values_profiler_atomic (gcov_type
*counters
, gcov_type value
)
128 __gcov_topn_values_profiler_body (counters
, value
, 1);
132 #ifdef L_gcov_indirect_call_profiler_v4
134 /* These two variables are used to actually track caller and callee. Keep
135 them in TLS memory so races are not common (they are written to often).
136 The variables are set directly by GCC instrumented code, so declaration
137 here must match one in tree-profile.c */
139 #if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
142 struct indirect_call_tuple __gcov_indirect_call
;
144 /* By default, the C++ compiler will use function addresses in the
145 vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
146 tells the compiler to use function descriptors instead. The value
147 of this macro says how many words wide the descriptor is (normally 2).
149 It is assumed that the address of a function descriptor may be treated
150 as a pointer to a function. */
152 /* Tries to determine the most common value among its inputs. */
154 __gcov_indirect_call_profiler_body (gcov_type value
, void *cur_func
,
157 /* If the C++ virtual tables contain function descriptors then one
158 function may have multiple descriptors and we need to dereference
159 the descriptors to see if they point to the same function. */
160 if (cur_func
== __gcov_indirect_call
.callee
161 || (__LIBGCC_VTABLE_USES_DESCRIPTORS__
162 && *(void **) cur_func
== *(void **) __gcov_indirect_call
.callee
))
163 __gcov_topn_values_profiler_body (__gcov_indirect_call
.counters
, value
,
166 __gcov_indirect_call
.callee
= NULL
;
170 __gcov_indirect_call_profiler_v4 (gcov_type value
, void *cur_func
)
172 __gcov_indirect_call_profiler_body (value
, cur_func
, 0);
175 #if GCOV_SUPPORTS_ATOMIC
177 __gcov_indirect_call_profiler_v4_atomic (gcov_type value
, void *cur_func
)
179 __gcov_indirect_call_profiler_body (value
, cur_func
, 1);
185 #ifdef L_gcov_time_profiler
187 /* Counter for first visit of each function. */
188 gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN
;
192 #ifdef L_gcov_average_profiler
193 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
197 __gcov_average_profiler (gcov_type
*counters
, gcov_type value
)
199 counters
[0] += value
;
204 #if defined(L_gcov_average_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
205 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
206 to saturate up. Function is thread-safe. */
209 __gcov_average_profiler_atomic (gcov_type
*counters
, gcov_type value
)
211 __atomic_fetch_add (&counters
[0], value
, __ATOMIC_RELAXED
);
212 __atomic_fetch_add (&counters
[1], 1, __ATOMIC_RELAXED
);
216 #ifdef L_gcov_ior_profiler
217 /* Bitwise-OR VALUE into COUNTER. */
220 __gcov_ior_profiler (gcov_type
*counters
, gcov_type value
)
226 #if defined(L_gcov_ior_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
227 /* Bitwise-OR VALUE into COUNTER. Function is thread-safe. */
230 __gcov_ior_profiler_atomic (gcov_type
*counters
, gcov_type value
)
232 __atomic_fetch_or (&counters
[0], value
, __ATOMIC_RELAXED
);
237 #endif /* inhibit_libc */