aarch64 - Set the mode for the unspec in speculation_tracker insn.
[platform/upstream/linaro-gcc.git] / gcc / gcov-tool.c
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014-2016 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 #if HAVE_FTW_H
39 #include <ftw.h>
40 #endif
41 #include <getopt.h>
42
43 extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
44 extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
45 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
46 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
47 extern struct gcov_info* gcov_read_profile_dir (const char*, int);
48 extern void gcov_do_dump (struct gcov_info *, int);
49 extern void gcov_set_verbose (void);
50
51 /* Set to verbose output mode.  */
52 static bool verbose;
53
54 #if HAVE_FTW_H
55
56 /* Remove file NAME if it has a gcda suffix. */
57
58 static int
59 unlink_gcda_file (const char *name,
60                   const struct stat *status ATTRIBUTE_UNUSED,
61                   int type ATTRIBUTE_UNUSED,
62                   struct FTW *ftwbuf ATTRIBUTE_UNUSED)
63 {
64   int ret = 0;
65   int len = strlen (name);
66   int len1 = strlen (GCOV_DATA_SUFFIX);
67
68   if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1))
69     ret = remove (name);
70
71   if (ret)
72     fatal_error (input_location, "error in removing %s\n", name);
73
74   return ret;
75 }
76 #endif
77
78 /* Remove the gcda files in PATH recursively.  */
79
80 static int
81 unlink_profile_dir (const char *path ATTRIBUTE_UNUSED)
82 {
83 #if HAVE_FTW_H
84     return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS);
85 #else
86     return -1;
87 #endif
88 }
89
90 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
91    we will remove all the gcda files in OUT.  */
92
93 static void
94 gcov_output_files (const char *out, struct gcov_info *profile)
95 {
96   char *pwd;
97   int ret;
98
99   /* Try to make directory if it doesn't already exist.  */
100   if (access (out, F_OK) == -1)
101     {
102       if (mkdir (out, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
103         fatal_error (input_location, "Cannot make directory %s", out);
104     } else
105       unlink_profile_dir (out);
106
107   /* Output new profile.  */
108   pwd = getcwd (NULL, 0);
109
110   if (pwd == NULL)
111     fatal_error (input_location, "Cannot get current directory name");
112
113   ret = chdir (out);
114   if (ret)
115     fatal_error (input_location, "Cannot change directory to %s", out);
116
117   gcov_do_dump (profile, 0);
118
119   ret = chdir (pwd);
120   if (ret)
121     fatal_error (input_location, "Cannot change directory to %s", pwd);
122
123   free (pwd);
124 }
125
126 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
127    The result profile is written to directory OUT.
128    Return 0 on success.  */
129
130 static int
131 profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2)
132 {
133   struct gcov_info *d1_profile;
134   struct gcov_info *d2_profile;
135   int ret;
136
137   d1_profile = gcov_read_profile_dir (d1, 0);
138   if (!d1_profile)
139     return 1;
140
141   if (d2)
142     {
143       d2_profile = gcov_read_profile_dir (d2, 0);
144       if (!d2_profile)
145         return 1;
146
147       /* The actual merge: we overwrite to d1_profile.  */
148       ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
149
150       if (ret)
151         return ret;
152     }
153
154   gcov_output_files (out, d1_profile);
155
156   return 0;
157 }
158
159 /* Usage message for profile merge.  */
160
161 static void
162 print_merge_usage_message (int error_p)
163 {
164   FILE *file = error_p ? stderr : stdout;
165
166   fnotice (file, "  merge [options] <dir1> <dir2>         Merge coverage file contents\n");
167   fnotice (file, "    -v, --verbose                       Verbose mode\n");
168   fnotice (file, "    -o, --output <dir>                  Output directory\n");
169   fnotice (file, "    -w, --weight <w1,w2>                Set weights (float point values)\n");
170 }
171
172 static const struct option merge_options[] =
173 {
174   { "verbose",                no_argument,       NULL, 'v' },
175   { "output",                 required_argument, NULL, 'o' },
176   { "weight",                 required_argument, NULL, 'w' },
177   { 0, 0, 0, 0 }
178 };
179
180 /* Print merge usage and exit.  */
181
182 static void
183 merge_usage (void)
184 {
185   fnotice (stderr, "Merge subcomand usage:");
186   print_merge_usage_message (true);
187   exit (FATAL_EXIT_CODE);
188 }
189
190 /* Driver for profile merge sub-command.  */
191
192 static int
193 do_merge (int argc, char **argv)
194 {
195   int opt;
196   const char *output_dir = 0;
197   int w1 = 1, w2 = 1;
198
199   optind = 0;
200   while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1)
201     {
202       switch (opt)
203         {
204         case 'v':
205           verbose = true;
206           gcov_set_verbose ();
207           break;
208         case 'o':
209           output_dir = optarg;
210           break;
211         case 'w':
212           sscanf (optarg, "%d,%d", &w1, &w2);
213           if (w1 < 0 || w2 < 0)
214             fatal_error (input_location, "weights need to be non-negative\n");
215           break;
216         default:
217           merge_usage ();
218         }
219     }
220
221   if (output_dir == NULL)
222     output_dir = "merged_profile";
223
224   if (argc - optind != 2)
225     merge_usage ();
226
227   return profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
228 }
229
230 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
231    counter value to N_VAL and scale others counters proportionally.
232    Otherwise, multiply the all counters by SCALE.  */
233
234 static int
235 profile_rewrite (const char *d1, const char *out, long long n_val,
236                  float scale, int n, int d)
237 {
238   struct gcov_info * d1_profile;
239
240   d1_profile = gcov_read_profile_dir (d1, 0);
241   if (!d1_profile)
242     return 1;
243
244   if (n_val)
245     gcov_profile_normalize (d1_profile, (gcov_type) n_val);
246   else
247     gcov_profile_scale (d1_profile, scale, n, d);
248
249   gcov_output_files (out, d1_profile);
250   return 0;
251 }
252
253 /* Usage function for profile rewrite.  */
254
255 static void
256 print_rewrite_usage_message (int error_p)
257 {
258   FILE *file = error_p ? stderr : stdout;
259
260   fnotice (file, "  rewrite [options] <dir>               Rewrite coverage file contents\n");
261   fnotice (file, "    -v, --verbose                       Verbose mode\n");
262   fnotice (file, "    -o, --output <dir>                  Output directory\n");
263   fnotice (file, "    -s, --scale <float or simple-frac>  Scale the profile counters\n");
264   fnotice (file, "    -n, --normalize <long long>         Normalize the profile\n");
265 }
266
267 static const struct option rewrite_options[] =
268 {
269   { "verbose",                no_argument,       NULL, 'v' },
270   { "output",                 required_argument, NULL, 'o' },
271   { "scale",                  required_argument, NULL, 's' },
272   { "normalize",              required_argument, NULL, 'n' },
273   { 0, 0, 0, 0 }
274 };
275
276 /* Print profile rewrite usage and exit.  */
277
278 static void
279 rewrite_usage (void)
280 {
281   fnotice (stderr, "Rewrite subcommand usage:");
282   print_rewrite_usage_message (true);
283   exit (FATAL_EXIT_CODE);
284 }
285
286 /* Driver for profile rewrite sub-command. */
287
288 static int
289 do_rewrite (int argc, char **argv)
290 {
291   int opt;
292   int ret;
293   const char *output_dir = 0;
294 #ifdef HAVE_LONG_LONG
295   long long normalize_val = 0;
296 #else
297   int64_t normalize_val = 0;
298 #endif
299   float scale = 0.0;
300   int numerator = 1;
301   int denominator = 1;
302   int do_scaling = 0;
303
304   optind = 0;
305   while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
306     {
307       switch (opt)
308         {
309         case 'v':
310           verbose = true;
311           gcov_set_verbose ();
312           break;
313         case 'o':
314           output_dir = optarg;
315           break;
316         case 'n':
317           if (!do_scaling)
318 #if defined(HAVE_LONG_LONG)
319             normalize_val = strtoll (optarg, (char **)NULL, 10);
320 #elif defined(INT64_T_IS_LONG)
321             normalize_val = strtol (optarg, (char **)NULL, 10);
322 #else
323             sscanf (optarg, "%" SCNd64, &normalize_val);
324 #endif
325           else
326             fnotice (stderr, "scaling cannot co-exist with normalization,"
327                 " skipping\n");
328           break;
329         case 's':
330           ret = 0;
331           do_scaling = 1;
332           if (strstr (optarg, "/"))
333             {
334               ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
335               if (ret == 2)
336                 {
337                   if (numerator < 0 || denominator <= 0)
338                     {
339                       fnotice (stderr, "incorrect format in scaling, using 1/1\n");
340                       denominator = 1;
341                       numerator = 1;
342                     }
343                 }
344             }
345           if (ret != 2)
346             {
347               ret = sscanf (optarg, "%f", &scale);
348               if (ret != 1)
349                 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
350               else
351                 denominator = 0;
352             }
353
354           if (scale < 0.0)
355             fatal_error (input_location, "scale needs to be non-negative\n");
356
357           if (normalize_val != 0)
358             {
359               fnotice (stderr, "normalization cannot co-exist with scaling\n");
360               normalize_val = 0;
361             }
362           break;
363         default:
364           rewrite_usage ();
365         }
366     }
367
368   if (output_dir == NULL)
369     output_dir = "rewrite_profile";
370
371   if (argc - optind == 1)
372     {
373       if (denominator > 0)
374         ret = profile_rewrite (argv[optind],  output_dir, 0, 0.0, numerator, denominator);
375       else
376         ret = profile_rewrite (argv[optind],  output_dir, normalize_val, scale, 0, 0);
377     }
378   else
379     rewrite_usage ();
380
381   return ret;
382 }
383
384 /* Driver function to computer the overlap score b/w profile D1 and D2.
385    Return 1 on error and 0 if OK.  */
386
387 static int
388 profile_overlap (const char *d1, const char *d2)
389 {
390   struct gcov_info *d1_profile;
391   struct gcov_info *d2_profile;
392
393   d1_profile = gcov_read_profile_dir (d1, 0);
394   if (!d1_profile)
395     return 1;
396
397   if (d2)
398     {
399       d2_profile = gcov_read_profile_dir (d2, 0);
400       if (!d2_profile)
401         return 1;
402
403       return gcov_profile_overlap (d1_profile, d2_profile);
404     }
405
406   return 1;
407 }
408
409 /* Usage message for profile overlap.  */
410
411 static void
412 print_overlap_usage_message (int error_p)
413 {
414   FILE *file = error_p ? stderr : stdout;
415
416   fnotice (file, "  overlap [options] <dir1> <dir2>       Compute the overlap of two profiles\n");
417   fnotice (file, "    -v, --verbose                       Verbose mode\n");
418   fnotice (file, "    -h, --hotonly                       Only print info for hot objects/functions\n");
419   fnotice (file, "    -f, --function                      Print function level info\n");
420   fnotice (file, "    -F, --fullname                      Print full filename\n");
421   fnotice (file, "    -o, --object                        Print object level info\n");
422   fnotice (file, "    -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
423
424 }
425
426 static const struct option overlap_options[] =
427 {
428   { "verbose",                no_argument,       NULL, 'v' },
429   { "function",               no_argument,       NULL, 'f' },
430   { "fullname",               no_argument,       NULL, 'F' },
431   { "object",                 no_argument,       NULL, 'o' },
432   { "hotonly",                no_argument,       NULL, 'h' },
433   { "hot_threshold",          required_argument, NULL, 't' },
434   { 0, 0, 0, 0 }
435 };
436
437 /* Print overlap usage and exit.  */
438
439 static void
440 overlap_usage (void)
441 {
442   fnotice (stderr, "Overlap subcomand usage:");
443   print_overlap_usage_message (true);
444   exit (FATAL_EXIT_CODE);
445 }
446
447 int overlap_func_level;
448 int overlap_obj_level;
449 int overlap_hot_only;
450 int overlap_use_fullname;
451 double overlap_hot_threshold = 0.005;
452
453 /* Driver for profile overlap sub-command.  */
454
455 static int
456 do_overlap (int argc, char **argv)
457 {
458   int opt;
459   int ret;
460
461   optind = 0;
462   while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
463     {
464       switch (opt)
465         {
466         case 'v':
467           verbose = true;
468           gcov_set_verbose ();
469           break;
470         case 'f':
471           overlap_func_level = 1;
472           break;
473         case 'F':
474           overlap_use_fullname = 1;
475           break;
476         case 'o':
477           overlap_obj_level = 1;
478           break;
479         case 'h':
480           overlap_hot_only = 1;
481           break;
482         case 't':
483           overlap_hot_threshold = atof (optarg);
484           break;
485         default:
486           overlap_usage ();
487         }
488     }
489
490   if (argc - optind == 2)
491     ret = profile_overlap (argv[optind], argv[optind+1]);
492   else
493     overlap_usage ();
494
495   return ret;
496 }
497
498
499 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
500    otherwise the output of --help.  */
501
502 static void
503 print_usage (int error_p)
504 {
505   FILE *file = error_p ? stderr : stdout;
506   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
507
508   fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname);
509   fnotice (file, "Offline tool to handle gcda counts\n\n");
510   fnotice (file, "  -h, --help                            Print this help, then exit\n");
511   fnotice (file, "  -v, --version                         Print version number, then exit\n");
512   print_merge_usage_message (error_p);
513   print_rewrite_usage_message (error_p);
514   print_overlap_usage_message (error_p);
515   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
516            bug_report_url);
517   exit (status);
518 }
519
520 /* Print version information and exit.  */
521
522 static void
523 print_version (void)
524 {
525   fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
526   fnotice (stdout, "Copyright %s 2014-2016 Free Software Foundation, Inc.\n",
527            _("(C)"));
528   fnotice (stdout,
529            _("This is free software; see the source for copying conditions.\n"
530              "There is NO warranty; not even for MERCHANTABILITY or \n"
531              "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
532   exit (SUCCESS_EXIT_CODE);
533 }
534
535 static const struct option options[] =
536 {
537   { "help",                 no_argument,       NULL, 'h' },
538   { "version",              no_argument,       NULL, 'v' },
539   { 0, 0, 0, 0 }
540 };
541
542 /* Process args, return index to first non-arg.  */
543
544 static int
545 process_args (int argc, char **argv)
546 {
547   int opt;
548
549   while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
550     {
551       switch (opt)
552         {
553         case 'h':
554           print_usage (false);
555           /* Print_usage will exit.  */
556           /* FALLTHRU */
557         case 'v':
558           print_version ();
559           /* Print_version will exit.  */
560           /* FALLTHRU */
561         default:
562           print_usage (true);
563           /* Print_usage will exit.  */
564         }
565     }
566
567   return optind;
568 }
569
570 /* Main function for gcov-tool.  */
571
572 int
573 main (int argc, char **argv)
574 {
575   const char *p;
576   const char *sub_command;
577
578   p = argv[0] + strlen (argv[0]);
579   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
580     --p;
581   progname = p;
582
583   xmalloc_set_program_name (progname);
584
585   /* Unlock the stdio streams.  */
586   unlock_std_streams ();
587
588   gcc_init_libintl ();
589
590   diagnostic_initialize (global_dc, 0);
591
592   /* Handle response files.  */
593   expandargv (&argc, &argv);
594
595   process_args (argc, argv);
596   if (optind >= argc)
597     print_usage (true);
598
599   sub_command = argv[optind];
600
601   if (!strcmp (sub_command, "merge"))
602     return do_merge (argc - optind, argv + optind);
603   else if (!strcmp (sub_command, "rewrite"))
604     return do_rewrite (argc - optind, argv + optind);
605   else if (!strcmp (sub_command, "overlap"))
606     return do_overlap (argc - optind, argv + optind);
607
608   print_usage (true);
609 }