reginfo.c: Use rtx_insn (also touches rtl.h)
[gcc.git] / gcc / gcov-tool.c
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014 Free Software Foundation, Inc.
3 Contributed by Rong Xu <xur@google.com>.
4
5 This file is part of GCC.
6
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
10 version.
11
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
15 for more details.
16
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.
20
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/>. */
25
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "intl.h"
31 #include "diagnostic.h"
32 #include "version.h"
33 #include "gcov-io.h"
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <ftw.h>
39 #include <getopt.h>
40
41 extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
42 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
43 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
44 extern struct gcov_info* gcov_read_profile_dir (const char*, int);
45 extern void gcov_do_dump (struct gcov_info *, int);
46 extern void gcov_set_verbose (void);
47
48 /* Set to verbose output mode. */
49 static bool verbose;
50
51 /* Remove file NAME if it has a gcda suffix. */
52
53 static int
54 unlink_gcda_file (const char *name,
55 const struct stat *status ATTRIBUTE_UNUSED,
56 int type ATTRIBUTE_UNUSED,
57 struct FTW *ftwbuf ATTRIBUTE_UNUSED)
58 {
59 int ret = 0;
60 int len = strlen (name);
61 int len1 = strlen (GCOV_DATA_SUFFIX);
62
63 if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1))
64 ret = remove (name);
65
66 if (ret)
67 fatal_error ("error in removing %s\n", name);
68
69 return ret;
70 }
71
72 /* Remove the gcda files in PATH recursively. */
73
74 static int
75 unlink_profile_dir (const char *path)
76 {
77 return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS);
78 }
79
80 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
81 we will remove all the gcda files in OUT. */
82
83 static void
84 gcov_output_files (const char *out, struct gcov_info *profile)
85 {
86 char *pwd;
87 int ret;
88
89 /* Try to make directory if it doesn't already exist. */
90 if (access (out, F_OK) == -1)
91 {
92 #if !defined(_WIN32)
93 if (mkdir (out, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
94 #else
95 if (mkdir (out) == -1 && errno != EEXIST)
96 #endif
97 fatal_error ("Cannot make directory %s", out);
98 } else
99 unlink_profile_dir (out);
100
101 /* Output new profile. */
102 pwd = getcwd (NULL, 0);
103
104 if (pwd == NULL)
105 fatal_error ("Cannot get current directory name");
106
107 ret = chdir (out);
108 if (ret)
109 fatal_error ("Cannot change directory to %s", out);
110
111 gcov_do_dump (profile, 0);
112
113 ret = chdir (pwd);
114 if (ret)
115 fatal_error ("Cannot change directory to %s", pwd);
116
117 free (pwd);
118 }
119
120 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
121 The result profile is written to directory OUT.
122 Return 0 on success. */
123
124 static int
125 profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2)
126 {
127 struct gcov_info *d1_profile;
128 struct gcov_info *d2_profile;
129 int ret;
130
131 d1_profile = gcov_read_profile_dir (d1, 0);
132 if (!d1_profile)
133 return 1;
134
135 if (d2)
136 {
137 d2_profile = gcov_read_profile_dir (d2, 0);
138 if (!d2_profile)
139 return 1;
140
141 /* The actual merge: we overwrite to d1_profile. */
142 ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
143
144 if (ret)
145 return ret;
146 }
147
148 gcov_output_files (out, d1_profile);
149
150 return 0;
151 }
152
153 /* Usage message for profile merge. */
154
155 static void
156 print_merge_usage_message (int error_p)
157 {
158 FILE *file = error_p ? stderr : stdout;
159
160 fnotice (file, " merge [options] <dir1> <dir2> Merge coverage file contents\n");
161 fnotice (file, " -v, --verbose Verbose mode\n");
162 fnotice (file, " -o, --output <dir> Output directory\n");
163 fnotice (file, " -w, --weight <w1,w2> Set weights (float point values)\n");
164 }
165
166 static const struct option merge_options[] =
167 {
168 { "verbose", no_argument, NULL, 'v' },
169 { "output", required_argument, NULL, 'o' },
170 { "weight", required_argument, NULL, 'w' },
171 { 0, 0, 0, 0 }
172 };
173
174 /* Print merge usage and exit. */
175
176 static void
177 merge_usage (void)
178 {
179 fnotice (stderr, "Merge subcomand usage:");
180 print_merge_usage_message (true);
181 exit (FATAL_EXIT_CODE);
182 }
183
184 /* Driver for profile merge sub-command. */
185
186 static int
187 do_merge (int argc, char **argv)
188 {
189 int opt;
190 int ret;
191 const char *output_dir = 0;
192 int w1 = 1, w2 = 1;
193
194 optind = 0;
195 while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1)
196 {
197 switch (opt)
198 {
199 case 'v':
200 verbose = true;
201 gcov_set_verbose ();
202 break;
203 case 'o':
204 output_dir = optarg;
205 break;
206 case 'w':
207 sscanf (optarg, "%d,%d", &w1, &w2);
208 if (w1 < 0 || w2 < 0)
209 fatal_error ("weights need to be non-negative\n");
210 break;
211 default:
212 merge_usage ();
213 }
214 }
215
216 if (output_dir == NULL)
217 output_dir = "merged_profile";
218
219 if (argc - optind == 2)
220 ret = profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
221 else
222 merge_usage ();
223
224 return ret;
225 }
226
227 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
228 counter value to N_VAL and scale others counters proportionally.
229 Otherwise, multiply the all counters by SCALE. */
230
231 static int
232 profile_rewrite (const char *d1, const char *out, long long n_val,
233 float scale, int n, int d)
234 {
235 struct gcov_info * d1_profile;
236
237 d1_profile = gcov_read_profile_dir (d1, 0);
238 if (!d1_profile)
239 return 1;
240
241 if (n_val)
242 gcov_profile_normalize (d1_profile, (gcov_type) n_val);
243 else
244 gcov_profile_scale (d1_profile, scale, n, d);
245
246 gcov_output_files (out, d1_profile);
247 return 0;
248 }
249
250 /* Usage function for profile rewrite. */
251
252 static void
253 print_rewrite_usage_message (int error_p)
254 {
255 FILE *file = error_p ? stderr : stdout;
256
257 fnotice (file, " rewrite [options] <dir> Rewrite coverage file contents\n");
258 fnotice (file, " -v, --verbose Verbose mode\n");
259 fnotice (file, " -o, --output <dir> Output directory\n");
260 fnotice (file, " -s, --scale <float or simple-frac> Scale the profile counters\n");
261 fnotice (file, " -n, --normalize <long long> Normalize the profile\n");
262 }
263
264 static const struct option rewrite_options[] =
265 {
266 { "verbose", no_argument, NULL, 'v' },
267 { "output", required_argument, NULL, 'o' },
268 { "scale", required_argument, NULL, 's' },
269 { "normalize", required_argument, NULL, 'n' },
270 { 0, 0, 0, 0 }
271 };
272
273 /* Print profile rewrite usage and exit. */
274
275 static void
276 rewrite_usage (void)
277 {
278 fnotice (stderr, "Rewrite subcommand usage:");
279 print_rewrite_usage_message (true);
280 exit (FATAL_EXIT_CODE);
281 }
282
283 /* Driver for profile rewrite sub-command. */
284
285 static int
286 do_rewrite (int argc, char **argv)
287 {
288 int opt;
289 int ret;
290 const char *output_dir = 0;
291 long long normalize_val = 0;
292 float scale = 0.0;
293 int numerator = 1;
294 int denominator = 1;
295 int do_scaling = 0;
296
297 optind = 0;
298 while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
299 {
300 switch (opt)
301 {
302 case 'v':
303 verbose = true;
304 gcov_set_verbose ();
305 break;
306 case 'o':
307 output_dir = optarg;
308 break;
309 case 'n':
310 if (!do_scaling)
311 normalize_val = atoll (optarg);
312 else
313 fnotice (stderr, "scaling cannot co-exist with normalization,"
314 " skipping\n");
315 break;
316 case 's':
317 ret = 0;
318 do_scaling = 1;
319 if (strstr (optarg, "/"))
320 {
321 ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
322 if (ret == 2)
323 {
324 if (numerator < 0 || denominator <= 0)
325 {
326 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
327 denominator = 1;
328 numerator = 1;
329 }
330 }
331 }
332 if (ret != 2)
333 {
334 ret = sscanf (optarg, "%f", &scale);
335 if (ret != 1)
336 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
337 else
338 denominator = 0;
339 }
340
341 if (scale < 0.0)
342 fatal_error ("scale needs to be non-negative\n");
343
344 if (normalize_val != 0)
345 {
346 fnotice (stderr, "normalization cannot co-exist with scaling\n");
347 normalize_val = 0;
348 }
349 break;
350 default:
351 rewrite_usage ();
352 }
353 }
354
355 if (output_dir == NULL)
356 output_dir = "rewrite_profile";
357
358 if (argc - optind == 1)
359 {
360 if (denominator > 0)
361 ret = profile_rewrite (argv[optind], output_dir, 0, 0.0, numerator, denominator);
362 else
363 ret = profile_rewrite (argv[optind], output_dir, normalize_val, scale, 0, 0);
364 }
365 else
366 rewrite_usage ();
367
368 return ret;
369 }
370
371 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
372 otherwise the output of --help. */
373
374 static void
375 print_usage (int error_p)
376 {
377 FILE *file = error_p ? stderr : stdout;
378 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
379
380 fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname);
381 fnotice (file, "Offline tool to handle gcda counts\n\n");
382 fnotice (file, " -h, --help Print this help, then exit\n");
383 fnotice (file, " -v, --version Print version number, then exit\n");
384 print_merge_usage_message (error_p);
385 print_rewrite_usage_message (error_p);
386 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
387 bug_report_url);
388 exit (status);
389 }
390
391 /* Print version information and exit. */
392
393 static void
394 print_version (void)
395 {
396 fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
397 fnotice (stdout, "Copyright %s 2014 Free Software Foundation, Inc.\n",
398 _("(C)"));
399 fnotice (stdout,
400 _("This is free software; see the source for copying conditions.\n"
401 "There is NO warranty; not even for MERCHANTABILITY or \n"
402 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
403 exit (SUCCESS_EXIT_CODE);
404 }
405
406 static const struct option options[] =
407 {
408 { "help", no_argument, NULL, 'h' },
409 { "version", no_argument, NULL, 'v' },
410 { 0, 0, 0, 0 }
411 };
412
413 /* Process args, return index to first non-arg. */
414
415 static int
416 process_args (int argc, char **argv)
417 {
418 int opt;
419
420 while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
421 {
422 switch (opt)
423 {
424 case 'h':
425 print_usage (false);
426 /* Print_usage will exit. */
427 case 'v':
428 print_version ();
429 /* Print_version will exit. */
430 default:
431 print_usage (true);
432 /* Print_usage will exit. */
433 }
434 }
435
436 return optind;
437 }
438
439 /* Main function for gcov-tool. */
440
441 int
442 main (int argc, char **argv)
443 {
444 const char *p;
445 const char *sub_command;
446
447 p = argv[0] + strlen (argv[0]);
448 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
449 --p;
450 progname = p;
451
452 xmalloc_set_program_name (progname);
453
454 /* Unlock the stdio streams. */
455 unlock_std_streams ();
456
457 gcc_init_libintl ();
458
459 diagnostic_initialize (global_dc, 0);
460
461 /* Handle response files. */
462 expandargv (&argc, &argv);
463
464 process_args (argc, argv);
465 if (optind >= argc)
466 print_usage (true);
467
468 sub_command = argv[optind];
469
470 if (!strcmp (sub_command, "merge"))
471 return do_merge (argc - optind, argv + optind);
472 else if (!strcmp (sub_command, "rewrite"))
473 return do_rewrite (argc - optind, argv + optind);
474
475 print_usage (true);
476 }