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