source: branches/stable/SOURCE_TOOLS/postcompile.pl

Last change on this file was 18014, checked in by westram, 5 years ago
  • always dump missed loop vectorizations.
  • if gcc regards a loop optimization as "too expensive", source requires IRRELEVANT_LOOP-comment ⇒ this revision fails compilation with 9.x series.
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1#!/usr/bin/perl
2# ================================================================= #
3#                                                                   #
4#   File      : postcompile.pl                                      #
5#   Purpose   : filter gcc shadow spam                              #
6#                                                                   #
7#   Coded by Ralf Westram (coder@reallysoft.de) in September 2007   #
8#   Institute of Microbiology (Technical University Munich)         #
9#   http://www.arb-home.de/                                         #
10#                                                                   #
11# ================================================================= #
12
13use strict;
14use warnings;
15
16# Note: g++ must be called with -fmessage-length=0
17
18my $show_suppressed_lines = 0;
19my $show_filtered_lines   = 0;
20
21# regexps for whole line:
22my $reg_file = qr/^([^:]+):([0-9]+):(([0-9]+):)?\s/; # finds all messages
23my $reg_file_noline = qr/^([^:]+):\s/; # finds all messages w/o linenumber (if not matched $reg_file)
24my $reg_included = qr/^In\sfile\sincluded\sfrom\s(.*)[,:]/;
25my $reg_inlined_from = qr/^\s\s+(inlined\sfrom\s.*)\sat\s(.*)[,:]/;
26my $reg_included2 = qr/^\s+from\s(.*)[,:]/;
27my $reg_location = qr/^[^:]+:\sIn\s(function|member\sfunction|instantiation)\s/;
28my $reg_location2 = qr/^[^:]+:\sAt\stop\slevel:/;
29my $reg_location3 = qr/^At\sglobal\sscope:/;
30my $reg_clang_dirt = qr/^ANALYZE:\s/;
31
32# regexps for messages:
33my $reg_is_error = qr/^error:\s/i;
34my $reg_is_warning = qr/^warning:\s/i;
35my $reg_is_note = qr/^note:\s/i;
36my $reg_is_instantiated = qr/^\s\s+instantiated\sfrom\s/;
37my $reg_is_required = qr/^\s\s+required\s(from|by)\s/;
38my $reg_is_optimizerMsg = qr/^(missed|optimized):\s/i;
39
40# regexps for warning messages (for part behind 'warning: ')
41my $reg_shadow_warning = qr/^declaration\sof\s.*\sshadows\s/;
42my $reg_shadow_location = qr/^shadowed\s/;
43my $reg_unknown_gcc_diagnostic = qr/^expected.*after\s'#pragma\sGCC\sdiagnostic'/;
44
45# filter unwanted -Weffc++ warnings
46my $filter_Weffpp = 1;
47my @reg_Weffpp = (
48                  qr/only\sdefines\sprivate\sconstructors\sand\shas\sno\sfriends/, # unwanted warning about singleton-class where the only instance exists as a static member of itself
49                  qr/^base\sclass\s.*has\s*(a|accessible)\snon-virtual\sdestructor/,
50                  qr/\sshould\sbe\sinitialized\sin\sthe\smember\sinitialization\slist/,
51                  qr/boost::icl::(insert|add)_iterator<ContainerT>.*should\sreturn/, # filter boost-iterator postfix operators warnings
52                  qr/^\s\sbut\sdoes\snot\soverride/, # belongs to reg_Weffpp_copyable
53                  qr/^\s\sor\s\'operator=/, # belongs to reg_Weffpp_copyable
54                 );
55
56my $filter_Weffpp_copyable = 0; # 1 = filter copy-ctor/op=-warning, 0 = check for Noncopyable and warn
57my $reg_Weffpp_copyable = qr/'(class|struct)\s([A-Za-z_0-9:]+).*'\shas\spointer\sdata\smembers/; # occurs also if derived from 'Noncopyable'
58
59# regexps for files:
60my $reg_user_include       = qr/^\/usr\/include\//;
61my $reg_HEADERLIBS_include = qr/\/HEADERLIBS\//;
62
63my $stop_after_first_error = 0;
64my $hide_warnings          = 0;
65
66my $dump_loop_optimization  = 0;
67my $check_loop_optimization = 0;
68my $checked_file = undef; # contains name of sourcefile (if it shall be checked)
69
70my $REQ_check_loop_optimization = 0; # originally requested?
71my $REQ_checked_file = 0; # originally checked file
72
73my $ARBHOME = $ENV{ARBHOME};
74my $exitcode = 0;
75
76# ----------------------------------------
77
78sub detect_needLoopCheck($) {
79  my ($source) = @_;
80  if ($check_loop_optimization) {
81    $REQ_check_loop_optimization = 1;
82    $REQ_checked_file = $source;
83    use Cwd;
84    my $currDir = Cwd::getcwd();
85    my $relDir = undef;
86    if ($currDir =~ /^$ARBHOME/) { $relDir = $'; }
87    if (not defined $relDir) { die "Can't detect ARBHOME-relative working directory"; }
88    $relDir =~ s/^\/*//og;
89    my $relfile = $relDir.'/'.$source;
90    my $checked_list = $ARBHOME.'/SOURCE_TOOLS/vectorized.source';
91
92    open(LIST,'<'.$checked_list) || die "can't read '$checked_list' (Reason: $!)";
93  SEARCH: foreach (<LIST>) {
94      if (not /^\s*\#/) { # ignore comments
95        if (not /^\s*$/) { # ignore empty lines
96          chomp($_);
97          if ($relfile eq $_) {
98            $checked_file = $source;
99            last SEARCH;
100          }
101        }
102      }
103    }
104    close(LIST);
105    if (not defined $checked_file) {
106      $check_loop_optimization = undef;
107    }
108    elsif ($dump_loop_optimization==2) {
109      $dump_loop_optimization = 0; # do not dump candidates, if file is already checked
110    }
111  }
112}
113
114sub getModtime($) {
115  my ($fileOrDir) = @_;
116  my $modtime = (stat($fileOrDir))[9];
117  return $modtime;
118}
119
120my %derived_from_NC = (); # key=classname, value=1/0
121my $NC_save_name = $ARBHOME.'/SOURCE_TOOLS/postcompile.sav';
122my $NC_loaded    = 0;
123my $NC_loaded_timestamp;
124my $NC_need_save = 0;
125
126sub load_from_NC() {
127  if (-f $NC_save_name) {
128    $NC_loaded_timestamp = getModtime($NC_save_name);
129    my $age = $NC_loaded_timestamp - time;
130    if ($age<3*60) { # never load data older than 3 min
131      open(NC,'<'.$NC_save_name);
132      foreach (<NC>) {
133        chomp;
134        if (/^([01]),/o) {
135          $derived_from_NC{$'} = $1;
136        }
137      }
138      close(NC);
139    }
140    else {
141      $NC_loaded_timestamp = 0; # epoch
142    }
143  }
144  else {
145    $NC_loaded_timestamp = 0; # epoch
146  }
147  $NC_loaded = 1;
148}
149
150sub save_from_NC() {
151  if ($NC_need_save==1) {
152    my $mt = 0;
153    if (-f $NC_save_name) { $mt = getModtime($NC_save_name); }
154    if ($mt>$NC_loaded_timestamp) { # changed on disk
155      load_from_NC(); # does simple merge
156    }
157    my $NC_save_name_private = $NC_save_name.'.'.$$;
158    open(NC,'>'.$NC_save_name_private);
159    foreach (sort keys %derived_from_NC) {
160      print NC $derived_from_NC{$_}.','.$_."\n";
161    }
162    close(NC);
163
164    rename($NC_save_name_private,$NC_save_name) || die "can't rename '$NC_save_name_private' to '$NC_save_name' (Reason: $!)";
165  }
166}
167
168sub advice_derived_from_Noncopyable($$$) {
169  # Note: you can silence the Noncopyable-warning by
170  # adding a comment containing 'Noncopyable' behind the 'class'-line
171  my ($classname,$file,$linenr) = @_;
172
173  if ($NC_loaded==0) { load_from_NC(); }
174  my $is_a_NC = $derived_from_NC{$classname};
175  if (defined $is_a_NC) {
176    return 0; # do not warn twice
177  }
178
179  if (not -f $file) {
180    die "no such file '$file'";
181  }
182
183  my $uq_classname = $classname;
184  while ($uq_classname =~ /::/o) { $uq_classname = $'; } # skip namespace prefixes
185
186  open(FILE,'<'.$file) || die "can't read '$file' (Reason: $!)";
187  my $line;
188  my $line_count = 0;
189 LINE: while (defined($line=<FILE>)) {
190    $line_count++;
191    if ($line_count==$linenr) {
192      if ($line =~ /(class|struct)\s+($uq_classname|$classname)(.*)Noncopyable/) {
193        my $prefix = $3;
194        if (not $prefix =~ /\/\//) { # if we have a comment, assume it mentions that the class is derived from a Noncopyable
195          if (not $prefix =~ /virtual/) {
196            print $file.':'.$linenr.': inheritance from Noncopyable should be virtual'."\n";
197          }
198        }
199        $is_a_NC = 1;
200      }
201      else { $is_a_NC = 0; }
202      last LINE;
203    }
204  }
205  close(FILE);
206  $derived_from_NC{$classname} = $is_a_NC;
207  $NC_need_save = 1;
208
209  return 1-$is_a_NC;
210}
211
212# results for Weffpp_warning_wanted():
213my $WANTED            = 0;
214my $WANTED_NO_RELATED = 1;
215my $UNWANTED          = 2;
216
217sub Weffpp_warning_wanted($$\$) {
218  my ($file,$line,$warning_text_r) = @_;
219
220  if ($filter_Weffpp==1) {
221    foreach my $reg (@reg_Weffpp) {
222      return $UNWANTED if ($$warning_text_r =~ $reg);
223    }
224    if ($$warning_text_r =~ $reg_Weffpp_copyable) {
225      my $classname = $2;
226      return $UNWANTED if ($filter_Weffpp_copyable==1);
227      return $UNWANTED if (advice_derived_from_Noncopyable($classname,$file,$line)==0);
228      $$warning_text_r = $$warning_text_r.' (and is neither derived from Noncopyable nor defines copy-ctor and op=)';
229      return $WANTED_NO_RELATED;
230    }
231  }
232  return $WANTED;
233}
234
235sub warning($\@) {
236  my ($msg,$out_r) = @_;
237  push @$out_r, '[postcompile/'.$$.']: '.$msg;
238}
239
240my $shadow_warning = undef;
241
242sub store_shadow($\@) {
243  my ($warn,$out_r) = @_;
244  if (defined $shadow_warning) {
245    warning('unprocessed shadow_warning:', @$out_r);
246    push @$out_r, $shadow_warning;
247  }
248  $shadow_warning = $warn;
249}
250
251my $last_pushed_related = 0;
252
253sub push_loc_and_related($$\@\@) {
254  my ($location_info,$message,$related_r,$out_r) = @_;
255  if (defined $location_info) {
256    push @$out_r, $location_info;
257  }
258  push @$out_r, $message;
259  $last_pushed_related = scalar(@$related_r);
260
261  # show related info (include-notes behind rest)
262  foreach (@$related_r) { if (not /included\sfrom/) { push @$out_r, $_; } }
263  foreach (@$related_r) { if (/included\sfrom/) { push @$out_r, $_; } }
264}
265
266sub drop_last_pushed_relateds(\@) {
267  my ($out_r) = @_;
268  if ($last_pushed_related>0) {
269    my $before_related = scalar(@$out_r) - $last_pushed_related - 1;
270    $before_related>=0 || die "impossible (out_r-elements=".scalar(@$out_r)."; last_pushed_related=$last_pushed_related)";
271    @$out_r = @$out_r[0 .. $before_related];
272  }
273}
274
275sub included_from_here($) {
276  my ($loc) = @_;
277  return $loc.': note: included from here';
278}
279
280sub suppress($\@$) {
281  my ($curr,$out_r,$as) = @_;
282  if ($show_suppressed_lines==1) {
283    warning('suppressed['.$as.']: '.$curr,@$out_r);
284  }
285  return undef;
286}
287
288sub is_system_or_builtin($) {
289  my ($file) = @_;
290  return (($file =~ $reg_user_include) or ($file eq '<built-in>') or ($file =~ $reg_HEADERLIBS_include));
291}
292
293sub suppress_shadow_warning_for($) {
294  my ($file) = @_;
295  return is_system_or_builtin($file);
296}
297
298sub compare_message_location($$) {
299  my ($a,$b) = @_;
300  # $a and $b are refs to array [filename location message]
301  my $cmp = $$a[0] cmp $$b[0]; # compare filenames
302  if ($cmp==0) {
303    my ($la,$lb) = (undef,undef);
304    if ($$a[1] =~ /^[0-9]+/o) { $la = $&; }
305    if ($$b[1] =~ /^[0-9]+/o) { $lb = $&; }
306    $cmp = $la <=> $lb; # compare line numbers
307  }
308  return $cmp;
309}
310sub compare_located_messages($$) {
311  my ($a,$b) = @_;
312  # $a and $b are refs to array [filename location message]
313  my $cmp = compare_message_location($a,$b);
314  if ($cmp==0) { $cmp = $$a[2] cmp $$b[2]; } # compare message
315  return $cmp;
316}
317
318sub grep_loop_comments($\@) {
319  my ($source,$hits_r) = @_;
320  open(SRC,'<'.$source) || die "can't read '$source' (Reason: $!)";
321  my $line;
322  my $linenr = 1;
323  while (defined($line=<SRC>)) {
324    if ($line =~ /(LOOP_VECTORIZED|IRRELEVANT_LOOP)/o) {
325      my $msg = $&.$';
326      chomp($msg);
327      push @$hits_r, [ $source, $linenr, $msg ];
328    }
329    $linenr++;
330  }
331  close(SRC);
332}
333
334sub numericCompilerVersion($\$) {
335  my ($versionStr,$err_r) = @_;
336  my $vs = $versionStr;
337  $vs =~ s/\.//og; # remove dots
338  if ($vs =~ /[^0-9]/o) { # check for invalid characters
339    $$err_r = "version contains invalid character: '$&'";
340    return undef;
341  }
342
343  my $versionNum = int($vs);
344  if ($versionNum<1) {
345    $$err_r = "Invalid compiler version '$versionStr'";
346    return undef;
347  }
348
349  while ($versionNum<100) {
350    $versionNum = $versionNum * 10; # assume sth like '6.3' was specified -> extend to 6.3.0
351  }
352  return $versionNum;
353}
354
355my $compilerVersion       = 'unknown'; # passed via CLI
356my $compilerVersionNumber = undef; # numeric compiler version (e.g. 443 or 720 for 4.4.3 resp. 7.2.0)
357
358sub calcVersionNumber() {
359  # calculate version-number of used compiler (called if specified)
360  die if defined $compilerVersionNumber;
361  my $cerr = undef;
362  $compilerVersionNumber = numericCompilerVersion($compilerVersion,$cerr);
363  if (defined $cerr) {
364    die "cannot interpret compiler version-number passed via CLI (Reason: $cerr)";
365  }
366}
367
368sub compiler_allowed_by($\$) {
369  my ($str,$err_r) = @_;
370  # checks if str contains exclusions in square-brackets.
371  # if yes -> check if compilerVersionNumber is excluded or not.
372  # return 0 if excluded, 1 if allowed.
373  # err_r is set in case of errors.
374
375  die if not defined $compilerVersionNumber;
376
377  my $exclusions;
378  while ($str =~ /\[([^\]]+)\]/o) {
379    ($str,$exclusions) = ($',$1);
380    my @conditions = split /\s*,\s*/,$exclusions;
381    my $compilerExcluded = 0;
382  CHECK: foreach my $cond (@conditions) {
383      if ($cond =~ /^!/o) {
384        my $rest =  $';
385        $rest    =~ s/\s//;
386
387        my $version_matches = 1;
388        my $op = '';
389      VERS: while ($version_matches and ($rest ne '')) {
390          if ($rest =~ /^([<>=]*)([^<>=])/o) {
391            ($op,$rest) = ($1,$2.$');
392          }
393
394          my $specVers;
395          if ($rest =~ /[<>=]/o) {
396            ($specVers,$rest) = ($`,$&.$');
397          }
398          else {
399            ($specVers,$rest) = ($rest,'');
400          }
401
402          my $cerr = undef;
403          my $version = numericCompilerVersion($specVers,$cerr);
404          if (defined $cerr) {
405            $$err_r = $cerr.' (in "'.$specVers.'")';
406            return 0;
407          }
408          if (not defined $version) { die "internal error: version undefined, but no error reported"; }
409
410          # document new operators in ./vectorize.README
411          if    ($op eq ''  ) { if ($compilerVersionNumber != $version) { $version_matches = 0; last VERS; } }
412          elsif ($op eq '<' ) { if ($compilerVersionNumber >= $version) { $version_matches = 0; last VERS; } }
413          elsif ($op eq '>' ) { if ($compilerVersionNumber <= $version) { $version_matches = 0; last VERS; } }
414          elsif ($op eq '<=') { if ($compilerVersionNumber >  $version) { $version_matches = 0; last VERS; } }
415          elsif ($op eq '>=') { if ($compilerVersionNumber <  $version) { $version_matches = 0; last VERS; } }
416          else {
417            $$err_r = "unknown exclude-operator '$op' (in '$cond')";
418            return 0;
419          }
420        }
421
422        if ($version_matches) {
423          $compilerExcluded = 1;
424          last CHECK;
425        }
426      }
427      else {
428        $$err_r = "unknown condition syntax in '$cond'";
429        return 0;
430      }
431    }
432    if ($compilerExcluded==1) { return 0; } # compiler not allowed
433  }
434  # no (matching) exclusions found -> compiler allowed
435  return 1;
436}
437
438my $trace_vectorization_success_messages = 0; # set to 1 to log messages which trigger "succeeded vectorization"
439sub is_successfulVectorizationMsg($) {
440  my ($msg) = @_;
441  if ($msg =~ /loop\svectorized/io) {
442    if ($msg =~ /not\svectorized/io) { die; return 0; }          # @@@ if this never happens -> remove
443    if ($msg =~ /basic\sblock\svectorized/io) { die; return 0; } # @@@ if this never happens -> remove
444    return 1;
445  }
446  return 0;
447}
448
449sub is_notWorthToVectorizeMsg($) {
450  my ($msg) = @_;
451  if ($msg =~ /cost.*worth/io) {
452    return 1;
453  }
454  return 0;
455}
456
457sub is_loopNote($) {
458  my ($msg) = @_;
459  if ($msg =~ /(loop|vectorized|misalign|versioning|optab|SLP|ssa-name)/io) { return 1; }
460
461  if ($msg =~ /bad\s(data)/io) { return 1; }
462  if ($msg =~ /basic\s(block)/io) { return 1; }
463  if ($msg =~ /not\s(supported)/io) { return 1; }
464  if ($msg =~ /step\s(unknown)/io) { return 1; }
465  if ($msg =~ /original\s(stmt)/io) { return 1; }
466  if ($msg =~ /cycle\s(pattern)/io) { return 1; }
467  if ($msg =~ /determine\s(dependence)/io) { return 1; }
468  if ($msg =~ /consecutive\s(access)/io) { return 1; }
469  if ($msg =~ /vector\s(alignment)/io) { return 1; }
470  if ($msg =~ /clobbers\s(memory)/io) { return 1; }
471  if ($msg =~ /cost.*worth/io) { return 1; }
472  if ($msg =~ /use\s(not)\s(simple)/io) { return 1; }
473  if ($msg =~ /no\s(array)\s(mode)/io) { return 1; }
474
475  if ($msg =~ /(unsupported|unknown|unexpected)\s(pattern)/io) { return 1; }
476
477  if ($msg =~ /interleaved.*(store)/io) { return 1; }
478  if ($msg =~ /vector.*(cost)/io) { return 1; }
479  if ($msg =~ /group.*too\s(large)/io) { return 1; }
480  if ($msg =~ /unary\/binary\/ternary/io) { return 1; }
481
482  return 0;
483}
484
485sub parse_input(\@) {
486  my ($out_r) = @_;
487  my @related = ();
488  my $location_info = undef;
489
490  my @warnout = ();
491  my @errout = ();
492  my @loopnote = (); # contains notes about loop-optimizations (refs to array [file line msg])
493
494  my $did_show_previous = 0;
495  my $is_error          = 0;
496  my $curr_out_r = \@warnout;
497
498 LINE: while (defined($_=<STDIN>)) {
499    chomp;
500    my $filter_current = 0;
501
502    next LINE if $_ eq '';
503
504    if ($_ =~ $reg_file) {
505      my ($file,$line,$msg) = ($1,$2,$');
506
507      if ($msg =~ $reg_is_warning) {
508        my $warn_text = $';
509
510        if ($warn_text =~ $reg_shadow_warning) {
511          if (not $' =~ /this/) { # don't store this warnings (no location follows)
512            store_shadow($_,@warnout);
513            $_ = suppress($_,@warnout, 'shadow-this');
514          }
515          elsif (suppress_shadow_warning_for($file)) {
516            $_ = suppress($_,@warnout, 'shadow');
517            # $location_info = undef;
518          }
519        }
520        elsif ($warn_text =~ $reg_shadow_location) {
521          if (not defined $shadow_warning) { warning('no shadow_warning seen',@warnout); }
522          else {
523            if (suppress_shadow_warning_for($file)) {
524              # don't warn about /usr/include or <built-in> shadowing
525              $_ = suppress($_,@warnout, 'shadowed');
526              @related = ();
527              $location_info = undef;
528            }
529            else {
530              if (defined $location_info) {
531                push @warnout, $location_info;
532                $location_info = undef;
533              }
534              push @warnout, $shadow_warning;
535            }
536            $shadow_warning = undef;
537          }
538        }
539        elsif ($warn_text =~ $reg_unknown_gcc_diagnostic) {
540          # filter warnings about unknown "pragma GCC diagnostic push/pop"
541          die if not defined $compilerVersionNumber;
542          if ($compilerVersionNumber<=447) {
543            $filter_current = 1; # ignore this warning
544          }
545          # otherwise show (affects 4.5.x; 4.6.x accepts push/pop)
546        }
547        else {
548          my $warn_is = Weffpp_warning_wanted($file,$line,$warn_text);
549          if ($warn_is == $UNWANTED) {
550            $filter_current = 1; # ignore this warning
551          }
552          elsif ($warn_is == $WANTED_NO_RELATED) {
553            @related = (); # drop related messages
554          }
555          # rebuild warning (Weffpp_warning_wanted might modify the message)
556          $_ = $file.':'.$line.': warning: '.$warn_text;
557        }
558        $is_error = 0;
559        $curr_out_r = \@warnout;
560      }
561      elsif ($msg =~ $reg_is_error) {
562        $is_error = 1;
563        $curr_out_r = \@errout;
564      }
565      elsif ($msg =~ $reg_is_instantiated) {
566        push @related, $_;
567        $_ = suppress($_,@warnout, 'instanciated');
568      }
569      elsif ($msg =~ $reg_is_required) {
570        push @related, $_;
571        $_ = suppress($_,@warnout, 'required');
572      }
573      elsif ($msg =~ $reg_is_note) {
574        my $note_after = 1; # 0->message follows note; 1->note follows message
575
576        my $note = $';
577        if (is_loopNote($note)==1) {
578          push @loopnote, [ $file, $line, $msg ];
579          $_ = suppress($_,@warnout, 'loop-note');
580        }
581        else {
582          if ($note_after==1) {
583            if ($did_show_previous==0) {
584              if (scalar(@loopnote)>0) {
585                push @loopnote, [ $file, $line, 'ASSUMING_LOOPNOTE [FIXME]: '.$msg ];
586                $_ = suppress($_,@warnout, 'loop-note');
587              }
588              else {
589                $_ = suppress($_,@warnout, 'note-of-nonshown');
590              }
591            }
592            else {
593              if ($msg =~ /in\sexpansion\sof\smacro/o) {
594                drop_last_pushed_relateds(@$curr_out_r);
595              }
596            }
597          }
598          else {
599            # note leads message -> store in related
600            push @related, $_;
601            $_ = suppress($_,@warnout, 'note');
602          }
603        }
604      }
605      elsif ($msg =~ $reg_is_optimizerMsg) { # message from optimized (gcc 9.1++)
606        my $note = $';
607        if (is_loopNote($note)==1) {
608          push @loopnote, [ $file, $line, $msg ];
609          $_ = suppress($_,@warnout, 'loop-note');
610        }
611        else {
612          $_ = suppress($_,@warnout, 'optimizerMsg-of-nonshown');
613        }
614      }
615    }
616    elsif ($_ =~ $reg_location or $_ =~ $reg_location2 or $_ =~ $reg_location3) {
617      $location_info = $_;
618      $_ = suppress($_,@warnout, 'location');
619    }
620    elsif ($_ =~ $reg_inlined_from) {
621      $_ = $2.': note: '.$1;
622      push @related, $_;
623      $_ = suppress($_,@warnout, 'inlined');
624    }
625    elsif ($_ =~ $reg_included) {
626      push @related, included_from_here($1);
627      $_ = suppress($_,@warnout, 'included');
628    }
629    elsif ($_ =~ $reg_clang_dirt) {
630      $_ = undef;
631    }
632    elsif ($_ =~ $reg_file_noline) {
633      if (/^(cc1plus|g\+\+|clang):.*error/o) {
634        ; # display normally
635      }
636      else {
637        # push @related, included_from_here($1);
638        push @related, $_;
639        $_ = suppress($_,@warnout, 'file-level-comment');
640      }
641    }
642    elsif (@related) {
643      if ($_ =~ $reg_included2) {
644        push @related, included_from_here($1);
645        $_ = suppress($_,@warnout, 'included2');
646      }
647    }
648
649    if (defined $_) {
650      if ($filter_current==0) {
651        if ($show_suppressed_lines==1) { warning('passing: '.$_, @warnout); }
652        push_loc_and_related($location_info,$_,@related,@$curr_out_r);
653        $did_show_previous = 1;
654
655        if (($is_error==1) and ($stop_after_first_error==1)) {
656          @warnout = (); # drop warnings
657          last LINE;
658        }
659      }
660      else {
661        die "can't filter errors (Error=$_)" if ($is_error==1);
662        if ($show_filtered_lines==1) { warning('filtered: '.$_, @$curr_out_r); }
663        $did_show_previous = 0;
664      }
665      $location_info = undef;
666      @related = ();
667    }
668  }
669
670  @$out_r = @errout;
671  if ($hide_warnings==0) { push @$out_r, @warnout; }
672
673  if ($dump_loop_optimization or $check_loop_optimization) {
674    # description of vectorization checks available in SOURCE_TOOLS/vectorize.README
675
676    my @loopmsg = ();
677    foreach my $vref (@loopnote) {
678      my ($file,$line,$msg) = @$vref;
679      my $boring = 0;
680      if ($msg =~ /completely\sunrolled/o) { $boring = 1; }
681      if (not $boring) { push @loopmsg, $vref; }
682    }
683
684    # sort messages and count + replace duplicates
685    @loopmsg = sort { compare_located_messages($a,$b); } @loopmsg;
686    {
687      my @undup_loopmsg = ();
688      my $seenDups = 0;
689      push @loopmsg, [ 'x', 0, '' ]; # append sentinel (forces proper counter for last message)
690      foreach (@loopmsg) {
691        my $prev = pop @undup_loopmsg;
692        if (defined $prev) {
693          if (compare_located_messages($prev,$_)!=0) {
694            if ($seenDups>0) { $$prev[2] = $$prev[2].' ['.($seenDups+1).'x]'; } # append counter
695            push @undup_loopmsg, $prev;
696            $seenDups = 0;
697          }
698          else { $seenDups++; }
699        }
700        push @undup_loopmsg, $_;
701      }
702      pop @undup_loopmsg;
703      @loopmsg = @undup_loopmsg;
704    }
705
706    my %loopfiles = map { $$_[0] => 1; } @loopmsg; # list of files for which loop-messages were found
707
708    if ($dump_loop_optimization) {
709      if (scalar(@loopmsg)) {
710        push @$out_r,  "---------------------------------------- dump_loop_optimization";
711        foreach my $vref (@loopmsg) {
712          my ($file,$line,$msg) = @$vref;
713          if ($dump_loop_optimization==1 or is_successfulVectorizationMsg($msg)==1) {
714            push @$out_r, "$file:$line: note: $msg";
715          }
716        }
717        push @$out_r,  "---------------------------------------- dump_loop_optimization [end]";
718        if ((not $check_loop_optimization) and ($REQ_check_loop_optimization==1) and ($dump_loop_optimization != 2)) {
719          my $vref = $loopmsg[0];
720          my $loc = $$vref[0].':'.$$vref[1];
721          push @$out_r,  "$loc: Warning: vectorization checks disabled in this file (need at least one vectorization-comment in ${REQ_checked_file})";
722        }
723      }
724    }
725    if ($check_loop_optimization || ($dump_loop_optimization==2)) {
726      my @comments = ();
727
728      if (defined $checked_file) {
729        grep_loop_comments($checked_file, @comments);
730
731        # read additional comments from included files:
732        delete $loopfiles{$checked_file};
733        foreach (keys %loopfiles) {
734          my @xtra_comments = ();
735          grep_loop_comments($_, @xtra_comments);
736          push @comments, @xtra_comments;
737        }
738      }
739
740      my $dump_comments = 0; # dump comments for debug purposes (should be disabled)
741      if ($dump_loop_optimization and $dump_comments) {
742        if (scalar(@comments)) {
743          push @$out_r,  "---------------------------------------- dump_detected_comments";
744          foreach my $cref (@comments) {
745            my ($file,$line,$msg) = @$cref;
746            push @$out_r, "$file:$line: $msg";
747          }
748          push @$out_r,  "---------------------------------------- dump_detected_comments [end]";
749        }
750      }
751
752      my $errors = 0;
753      foreach my $cref (@comments) {
754        my $loc  = $$cref[0].':'.$$cref[1];
755        my $cmsg = $$cref[2];
756
757        my $was_vectorized          = 0;
758        my $worthless_vectorization = 0;
759        foreach my $vref (@loopmsg) {
760          if (compare_message_location($cref,$vref)==0) {
761            my $vmsg = $$vref[2];
762            if (is_successfulVectorizationMsg($vmsg)==1) {
763              if ($trace_vectorization_success_messages==1) {
764                push @$out_r, "$loc: Note: vectorized message='$vmsg'";
765              }
766              if ($vmsg =~ /\[([0-9]+)x\]/o) { # vectorized multiple times (e.g. in template)
767                $was_vectorized = $1;
768              }
769              else {
770                $was_vectorized = 1;
771              }
772            }
773            elsif (is_notWorthToVectorizeMsg($vmsg)==1) {
774              $worthless_vectorization = 1;
775            }
776          }
777        }
778        if ($cmsg =~ /^LOOP_VECTORIZED/o) {
779          my $rest   = $';
780          my $errmsg = undef;
781
782          my $applies_to_compiler = compiler_allowed_by($rest,$errmsg); # check for exclusions of specific compiler versions
783
784          if (defined $errmsg) {
785            push @$out_r, "$loc: Error: in vectorize-condition: $errmsg";
786            $errors++;
787          }
788          elsif (not $was_vectorized) {
789            if ($worthless_vectorization==1) {
790              push @$out_r, "$loc: Error: possible but worthless loop vectorization rejected -> use IRRELEVANT_LOOP (compiler version=$compilerVersion)";
791              $errors++;
792            }
793            elsif ($applies_to_compiler==1) {
794              push @$out_r, "$loc: Error: loop vectorization failed (compiler version=$compilerVersion)";
795              $errors++;
796            }
797            # otherwise silently handled like IRRELEVANT_LOOP
798          }
799          else {
800            if ($applies_to_compiler==0) { # compiler excluded, but vectorization occurred
801              push @$out_r, "$loc: Error: loop vectorization succeeded (but compiler version '$compilerVersion' excluded by condition)";
802              $errors++;
803            }
804            elsif ($rest =~ /^=([0-9]+|\*)/o) {
805              my $expect_multiple = $1;
806              if ($expect_multiple ne '*') { # allow any number of instantiations
807                if ($expect_multiple!=$was_vectorized) {
808                  push @$out_r, "$loc: Error: vectorization count mismatch (specified=$expect_multiple, found=$was_vectorized)";
809                  $errors++;
810                }
811              }
812            }
813            elsif ($was_vectorized>1) {
814                push @$out_r, "$loc: Warning: loop gets vectorized $was_vectorized times";
815                push @$out_r, "$loc: Note: Comment with LOOP_VECTORIZED=$was_vectorized to force check of number of instantiations";
816                push @$out_r, "$loc: Note: Comment with LOOP_VECTORIZED=* to hide this warning";
817            }
818          }
819        }
820      }
821
822      foreach my $vref (@loopmsg) {
823        my $vmsg = $$vref[2];
824        if (is_successfulVectorizationMsg($vmsg)==1) {
825          my $loc  = $$vref[0].':'.$$vref[1];
826          if ($trace_vectorization_success_messages==1) {
827            push @$out_r, "$loc: Note: vectorized message='$vmsg'";
828          }
829          my $has_loop_comment = undef;
830          foreach my $cref (@comments) {
831            if (compare_message_location($cref,$vref)==0) {
832              $has_loop_comment = $$cref[2];
833            }
834          }
835          if (not defined $has_loop_comment) {
836            push @$out_r, "$loc: Warning: Unchecked optimized loop";
837            push @$out_r, "$loc: Note: Comment with LOOP_VECTORIZED to force check";
838            push @$out_r, "$loc: Note: Comment with IRRELEVANT_LOOP to hide this warning";
839          }
840        }
841      }
842      if ($errors) { $exitcode = 1; }
843    }
844  }
845}
846
847sub die_usage($) {
848  my ($err) = @_;
849  print "Usage: postcompile.pl [Options] sourcefile\n";
850  print "Used as compilation output filter for C/C++\n";
851  print "Options:\n";
852  print "    --no-warnings                 hide warnings (plus related messages)\n";
853  print "    --only-first-error            show only first error\n";
854  print "    --original                    pass-through\n";
855  print "    --show-useless-Weff++         do not suppress useless -Weff++ warnings\n";
856  print "    --hide-Noncopyable-advices    do not advice about using Noncopyable\n";
857  print "    --compiler=version            needed for --check-loop-optimization (version e.g. '4.9.1')\n";
858  print "    --dump-loop-optimization      dump (most) notes related to loop vectorization\n";
859  print "    --loop-optimization-candi     show candidates for loop vectorization-check\n";
860  print "    --check-loop-optimization     if sourcefile is listed in \$ARBHOME/SOURCE_TOOLS/vectorized.source,\n";
861  print "                                  => check commented loops have been vectorized\n";
862
863  if (defined $err) {
864    die "Error in postcompile.pl: $err";
865  }
866}
867
868sub set_dump_loop_optimization($) {
869  my ($val) = @_;
870  die if $val==0;
871  if ($dump_loop_optimization==0) {
872    $dump_loop_optimization = $val;
873  }
874  else {
875    die "dump_loop_optimization already set (old=$dump_loop_optimization; new=$val)";
876    # may e.g. happen when using --dump-loop-optimization AND --loop-optimization-candi
877  }
878}
879
880sub main() {
881  my $args = scalar(@ARGV);
882  my $pass_through = 0;
883  my $sourcefile = undef;
884  while ($args>0) {
885    my $arg = shift(@ARGV);
886    if    ($arg eq '--no-warnings') { $hide_warnings = 1; }
887    elsif ($arg eq '--only-first-error') { $stop_after_first_error = 1; }
888    elsif ($arg eq '--original') { $pass_through = 1; }
889    elsif ($arg eq '--show-useless-Weff++') { $filter_Weffpp = 0; }
890    elsif ($arg eq '--hide-Noncopyable-advices') { $filter_Weffpp_copyable = 1; }
891    elsif ($arg eq '--dump-loop-optimization') { set_dump_loop_optimization(1); }
892    elsif ($arg eq '--loop-optimization-candi') { set_dump_loop_optimization(2); }
893    elsif ($arg eq '--check-loop-optimization') { $check_loop_optimization = 1; }
894    elsif ($arg =~ /^--compiler=/o) { $compilerVersion = $'; calcVersionNumber(); }
895    elsif (not defined $sourcefile) { $sourcefile = $arg; }
896    else {
897      die_usage("Unknown argument '$arg'");
898    }
899    $args--;
900  }
901
902  defined $sourcefile || die_usage("missing argument 'sourcefile'");
903  if (not -f $sourcefile) { die "Unknown sourcefile '$sourcefile'"; }
904
905  eval {
906    if ($pass_through==1) {
907      while (defined($_=<STDIN>)) { print $_; }
908    }
909    else {
910      my @out = ();
911      detect_needLoopCheck($sourcefile);
912      parse_input(@out);
913      store_shadow(undef,@out);
914      foreach (@out) { print "$_\n"; }
915    }
916  };
917  my $err = $@;
918  save_from_NC();
919  if ($err) { die $err; }
920}
921main();
922exit $exitcode;
Note: See TracBrowser for help on using the repository browser.