1*38fd1498Szrj /* Routines required for instrumenting a program. */
2*38fd1498Szrj /* Compile this one with gcc. */
3*38fd1498Szrj /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
4*38fd1498Szrj
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
8*38fd1498Szrj the terms of the GNU General Public License as published by the Free
9*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
10*38fd1498Szrj version.
11*38fd1498Szrj
12*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15*38fd1498Szrj for more details.
16*38fd1498Szrj
17*38fd1498Szrj Under Section 7 of GPL version 3, you are granted additional
18*38fd1498Szrj permissions described in the GCC Runtime Library Exception, version
19*38fd1498Szrj 3.1, as published by the Free Software Foundation.
20*38fd1498Szrj
21*38fd1498Szrj You should have received a copy of the GNU General Public License and
22*38fd1498Szrj a copy of the GCC Runtime Library Exception along with this program;
23*38fd1498Szrj see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24*38fd1498Szrj <http://www.gnu.org/licenses/>. */
25*38fd1498Szrj
26*38fd1498Szrj #include "libgcov.h"
27*38fd1498Szrj
28*38fd1498Szrj #if defined(inhibit_libc)
29*38fd1498Szrj /* If libc and its header files are not available, provide dummy functions. */
30*38fd1498Szrj
31*38fd1498Szrj #ifdef L_gcov_merge_add
__gcov_merge_add(gcov_type * counters,unsigned n_counters)32*38fd1498Szrj void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)),
33*38fd1498Szrj unsigned n_counters __attribute__ ((unused))) {}
34*38fd1498Szrj #endif
35*38fd1498Szrj
36*38fd1498Szrj #ifdef L_gcov_merge_single
__gcov_merge_single(gcov_type * counters,unsigned n_counters)37*38fd1498Szrj void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)),
38*38fd1498Szrj unsigned n_counters __attribute__ ((unused))) {}
39*38fd1498Szrj #endif
40*38fd1498Szrj
41*38fd1498Szrj #else
42*38fd1498Szrj
43*38fd1498Szrj #ifdef L_gcov_merge_add
44*38fd1498Szrj /* The profile merging function that just adds the counters. It is given
45*38fd1498Szrj an array COUNTERS of N_COUNTERS old counters and it reads the same number
46*38fd1498Szrj of counters from the gcov file. */
47*38fd1498Szrj void
__gcov_merge_add(gcov_type * counters,unsigned n_counters)48*38fd1498Szrj __gcov_merge_add (gcov_type *counters, unsigned n_counters)
49*38fd1498Szrj {
50*38fd1498Szrj for (; n_counters; counters++, n_counters--)
51*38fd1498Szrj *counters += gcov_get_counter ();
52*38fd1498Szrj }
53*38fd1498Szrj #endif /* L_gcov_merge_add */
54*38fd1498Szrj
55*38fd1498Szrj #ifdef L_gcov_merge_ior
56*38fd1498Szrj /* The profile merging function that just adds the counters. It is given
57*38fd1498Szrj an array COUNTERS of N_COUNTERS old counters and it reads the same number
58*38fd1498Szrj of counters from the gcov file. */
59*38fd1498Szrj void
__gcov_merge_ior(gcov_type * counters,unsigned n_counters)60*38fd1498Szrj __gcov_merge_ior (gcov_type *counters, unsigned n_counters)
61*38fd1498Szrj {
62*38fd1498Szrj for (; n_counters; counters++, n_counters--)
63*38fd1498Szrj *counters |= gcov_get_counter_target ();
64*38fd1498Szrj }
65*38fd1498Szrj #endif
66*38fd1498Szrj
67*38fd1498Szrj #ifdef L_gcov_merge_time_profile
68*38fd1498Szrj /* Time profiles are merged so that minimum from all valid (greater than zero)
69*38fd1498Szrj is stored. There could be a fork that creates new counters. To have
70*38fd1498Szrj the profile stable, we chosen to pick the smallest function visit time. */
71*38fd1498Szrj void
__gcov_merge_time_profile(gcov_type * counters,unsigned n_counters)72*38fd1498Szrj __gcov_merge_time_profile (gcov_type *counters, unsigned n_counters)
73*38fd1498Szrj {
74*38fd1498Szrj unsigned int i;
75*38fd1498Szrj gcov_type value;
76*38fd1498Szrj
77*38fd1498Szrj for (i = 0; i < n_counters; i++)
78*38fd1498Szrj {
79*38fd1498Szrj value = gcov_get_counter_target ();
80*38fd1498Szrj
81*38fd1498Szrj if (value && (!counters[i] || value < counters[i]))
82*38fd1498Szrj counters[i] = value;
83*38fd1498Szrj }
84*38fd1498Szrj }
85*38fd1498Szrj #endif /* L_gcov_merge_time_profile */
86*38fd1498Szrj
87*38fd1498Szrj #ifdef L_gcov_merge_single
88*38fd1498Szrj /* The profile merging function for choosing the most common value.
89*38fd1498Szrj It is given an array COUNTERS of N_COUNTERS old counters and it
90*38fd1498Szrj reads the same number of counters from the gcov file. The counters
91*38fd1498Szrj are split into 3-tuples where the members of the tuple have
92*38fd1498Szrj meanings:
93*38fd1498Szrj
94*38fd1498Szrj -- the stored candidate on the most common value of the measured entity
95*38fd1498Szrj -- counter
96*38fd1498Szrj -- total number of evaluations of the value */
97*38fd1498Szrj void
__gcov_merge_single(gcov_type * counters,unsigned n_counters)98*38fd1498Szrj __gcov_merge_single (gcov_type *counters, unsigned n_counters)
99*38fd1498Szrj {
100*38fd1498Szrj unsigned i, n_measures;
101*38fd1498Szrj gcov_type value, counter, all;
102*38fd1498Szrj
103*38fd1498Szrj gcc_assert (!(n_counters % 3));
104*38fd1498Szrj n_measures = n_counters / 3;
105*38fd1498Szrj for (i = 0; i < n_measures; i++, counters += 3)
106*38fd1498Szrj {
107*38fd1498Szrj value = gcov_get_counter_target ();
108*38fd1498Szrj counter = gcov_get_counter ();
109*38fd1498Szrj all = gcov_get_counter ();
110*38fd1498Szrj
111*38fd1498Szrj if (counters[0] == value)
112*38fd1498Szrj counters[1] += counter;
113*38fd1498Szrj else if (counter > counters[1])
114*38fd1498Szrj {
115*38fd1498Szrj counters[0] = value;
116*38fd1498Szrj counters[1] = counter - counters[1];
117*38fd1498Szrj }
118*38fd1498Szrj else
119*38fd1498Szrj counters[1] -= counter;
120*38fd1498Szrj counters[2] += all;
121*38fd1498Szrj }
122*38fd1498Szrj }
123*38fd1498Szrj #endif /* L_gcov_merge_single */
124*38fd1498Szrj
125*38fd1498Szrj #ifdef L_gcov_merge_icall_topn
126*38fd1498Szrj /* The profile merging function used for merging indirect call counts
127*38fd1498Szrj This function is given array COUNTERS of N_COUNTERS old counters and it
128*38fd1498Szrj reads the same number of counters from the gcov file. */
129*38fd1498Szrj
130*38fd1498Szrj void
__gcov_merge_icall_topn(gcov_type * counters,unsigned n_counters)131*38fd1498Szrj __gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters)
132*38fd1498Szrj {
133*38fd1498Szrj unsigned i, j, k, m;
134*38fd1498Szrj
135*38fd1498Szrj gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS));
136*38fd1498Szrj for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS)
137*38fd1498Szrj {
138*38fd1498Szrj gcov_type *value_array = &counters[i + 1];
139*38fd1498Szrj unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1);
140*38fd1498Szrj gcov_type *tmp_array
141*38fd1498Szrj = (gcov_type *) alloca (tmp_size * sizeof (gcov_type));
142*38fd1498Szrj
143*38fd1498Szrj for (j = 0; j < tmp_size; j++)
144*38fd1498Szrj tmp_array[j] = 0;
145*38fd1498Szrj
146*38fd1498Szrj for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2)
147*38fd1498Szrj {
148*38fd1498Szrj tmp_array[j] = value_array[j];
149*38fd1498Szrj tmp_array[j + 1] = value_array [j + 1];
150*38fd1498Szrj }
151*38fd1498Szrj
152*38fd1498Szrj /* Skip the number_of_eviction entry. */
153*38fd1498Szrj gcov_get_counter ();
154*38fd1498Szrj for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
155*38fd1498Szrj {
156*38fd1498Szrj int found = 0;
157*38fd1498Szrj gcov_type global_id = gcov_get_counter_target ();
158*38fd1498Szrj gcov_type call_count = gcov_get_counter ();
159*38fd1498Szrj for (m = 0; m < j; m += 2)
160*38fd1498Szrj {
161*38fd1498Szrj if (tmp_array[m] == global_id)
162*38fd1498Szrj {
163*38fd1498Szrj found = 1;
164*38fd1498Szrj tmp_array[m + 1] += call_count;
165*38fd1498Szrj break;
166*38fd1498Szrj }
167*38fd1498Szrj }
168*38fd1498Szrj if (!found)
169*38fd1498Szrj {
170*38fd1498Szrj tmp_array[j] = global_id;
171*38fd1498Szrj tmp_array[j + 1] = call_count;
172*38fd1498Szrj j += 2;
173*38fd1498Szrj }
174*38fd1498Szrj }
175*38fd1498Szrj /* Now sort the temp array */
176*38fd1498Szrj gcov_sort_n_vals (tmp_array, j);
177*38fd1498Szrj
178*38fd1498Szrj /* Now copy back the top half of the temp array */
179*38fd1498Szrj for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2)
180*38fd1498Szrj {
181*38fd1498Szrj value_array[k] = tmp_array[k];
182*38fd1498Szrj value_array[k + 1] = tmp_array[k + 1];
183*38fd1498Szrj }
184*38fd1498Szrj }
185*38fd1498Szrj }
186*38fd1498Szrj #endif /* L_gcov_merge_icall_topn */
187*38fd1498Szrj #endif /* inhibit_libc */
188