source: branches/ali/SOURCE_TOOLS/postcompile.pl

Last change on this file was 19440, checked in by westram, 21 months ago
  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 33.8 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\s(override|declare)/, # belongs to reg_Weffpp_copyable (since gcc 10.2.0 message uses 'declare' instead of 'override')
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<443) { # for lowest allowed version see ../Makefile@ALLOWED_gcc_VERSIONS
350    # assume shortened compiler version was specified + extend it:
351    # e.g. '6.3' -> 630
352    #      '10'  -> 1000
353    #      '4'  -> 4000 (this would be gcc 40.x)
354    $versionNum = $versionNum * 10;
355  }
356
357  return $versionNum;
358}
359
360my $compilerVersion       = 'unknown'; # passed via CLI
361my $compilerVersionNumber = undef; # numeric compiler version (e.g. 443 or 720 for 4.4.3 resp. 7.2.0)
362
363sub calcVersionNumber() {
364  # calculate version-number of used compiler (called if specified)
365  die if defined $compilerVersionNumber;
366  my $cerr = undef;
367  $compilerVersionNumber = numericCompilerVersion($compilerVersion,$cerr);
368  if (defined $cerr) {
369    die "cannot interpret compiler version-number passed via CLI (Reason: $cerr)";
370  }
371}
372
373sub compiler_allowed_by($\$) {
374  my ($exclusions,$err_r) = @_;
375  # checks if 'exclusions' allow global 'compilerVersionNumber'.
376  # return 0 if excluded, 1 if allowed.
377  # 'err_r' is set in case of errors.
378
379  die if not defined $compilerVersionNumber;
380
381  my @conditions = split /\s*,\s*/,$exclusions;
382
383  my $compilerExcluded = 0;
384 CHECK: foreach my $cond (@conditions) {
385    my ($exclude,$rest);
386    if ($cond =~ /^!/o) {
387      $exclude = 1;
388      $cond = $';
389      ($exclude,$rest) = (1,$');
390    }
391    else {
392      ($exclude,$rest) = (0,$cond);
393    }
394
395    $rest =~ s/\s//;
396
397    print "cond='$cond' exclude=$exclude\n";
398
399    my $cond_matches = 1;
400    my $op = '';
401  VERS: while ($rest ne '') {
402      if ($rest =~ /^([<>=]*)([^<>=])/o) {
403        ($op,$rest) = ($1,$2.$');
404      }
405
406      my $specVers;
407      if ($rest =~ /[<>=]/o) {
408        ($specVers,$rest) = ($`,$&.$');
409      }
410      else {
411        ($specVers,$rest) = ($rest,'');
412      }
413
414      my $cerr = undef;
415      my $version = numericCompilerVersion($specVers,$cerr);
416      if (defined $cerr) {
417        $$err_r = $cerr.' (in "'.$specVers.'")';
418        return 0;
419      }
420      if (not defined $version) { die "internal error: version undefined, but no error reported"; }
421
422      # document new operators in ./vectorize.README
423      if    ($op eq ''  ) { if ($compilerVersionNumber != $version) { $cond_matches = 0; } }
424      elsif ($op eq '<' ) { if ($compilerVersionNumber >= $version) { $cond_matches = 0; } }
425      elsif ($op eq '>' ) { if ($compilerVersionNumber <= $version) { $cond_matches = 0; } }
426      elsif ($op eq '<=') { if ($compilerVersionNumber >  $version) { $cond_matches = 0; } }
427      elsif ($op eq '>=') { if ($compilerVersionNumber <  $version) { $cond_matches = 0; } }
428      else {
429        $$err_r = "unknown exclude-operator '$op' (in '$cond')";
430        return 0;
431      }
432
433      print "cond_matches=$cond_matches rest='$rest'\n";
434    }
435
436    if ($cond_matches == $exclude) {
437      $compilerExcluded = 1;
438      last CHECK;
439    }
440  }
441
442  print "compilerExcluded=$compilerExcluded\n";
443  return $compilerExcluded ? 0 : 1;
444}
445
446
447sub parse_expected_vectorizations($\$) {
448  my ($str,$err_r) = @_;
449
450  # 'str' is rest of line behind 'LOOP_VECTORIZED'.
451  # Expected syntax is described in ./vectorize.README@LOOP_VECTORIZED
452  # 'err_r' gets set in case of error (caller abort when set!)
453  # result is number of expected vectorizations (depends on global 'compilerVersionNumber')
454
455  my $expected_vectorizations = 0;
456  my $condition_matched       = 0;
457
458  while (not $condition_matched and not defined $$err_r) {
459    my $seen_num = 1;
460    if ($str =~ /^\s*=([0-9\*\|]+)/o) { # str begins with '=<num>' or '=<num>'['|<num>']+
461      my ($num,$rest) = ($1,$');
462      if ($num =~ /\*/o) {
463        $$err_r = "vectorization count may not contain '*' (specify explicit numbers conditionally, e.g. '=3[!>=950]=1')";
464      }
465      else {
466        if ($num =~ /\|/o) {
467          my @num_list = split /\|/, $num;
468          foreach my $n (@num_list) {
469            my $nn = int($n);
470            if (not $nn) {
471              if (not $n =~ /0/o) {
472                $$err_r = "invalid count '$n' in '$str'";
473              }
474              else {
475                $$err_r = "zero vectorization count is not useful here (consider using IRRELEVANT_LOOP)";
476              }
477            }
478          }
479          $expected_vectorizations = \@num_list;
480        }
481        else {
482          $expected_vectorizations = int($num);
483          if (not $expected_vectorizations and not $num =~ /0/o) {
484            $$err_r = "invalid count '$num' in '$str'";
485          }
486        }
487      }
488      $str = $rest;
489    }
490    else { # no '=<num>'-prefix
491      if (not $expected_vectorizations) { # first <count> -> default to 1
492        $expected_vectorizations = 1;
493      }
494      else {
495        $seen_num = 0;
496      }
497    }
498
499    if ($str =~ /\s*\[([^\]]+)\]/o) { # condition follows
500      # if not 'seen_num' => accept following condition as alternative (OR-operation)
501      my ($cond, $rest) = ($1,$');
502      if ($condition_matched) {
503        $$err_r = "unexpected condition '$cond' (did you forget a '=count'-prefix?)";
504      }
505      else {
506        my $allowed = compiler_allowed_by($cond,$$err_r);
507        if (defined $$err_r) {
508          ;
509        }
510        else {
511          if ($allowed) { $condition_matched = 1; }
512        }
513      }
514      $str = $rest;
515    }
516    else {
517      # no condition follows -> always fulfilled
518      $condition_matched = 1;
519      if (not $seen_num) { $expected_vectorizations = 0; } # no condition after no count => expect failure for all compilers that did not match before
520    }
521  }
522
523  return $expected_vectorizations;
524}
525
526my $trace_vectorization_success_messages = 0; # set to 1 to log messages which trigger "succeeded vectorization"
527sub is_successfulVectorizationMsg($) {
528  my ($msg) = @_;
529  if ($msg =~ /loop\svectorized/io) {
530    if ($msg =~ /not\svectorized/io) { die; return 0; }          # @@@ if this never happens -> remove
531    if ($msg =~ /basic\sblock\svectorized/io) { die; return 0; } # @@@ if this never happens -> remove
532    return 1;
533  }
534  return 0;
535}
536
537sub is_notWorthToVectorizeMsg($) {
538  my ($msg) = @_;
539  if ($msg =~ /cost.*worth/io) {
540    return 1;
541  }
542  return 0;
543}
544
545sub is_loopNote($) {
546  my ($msg) = @_;
547  if ($msg =~ /(loop|vectorized|misalign|versioning|optab|SLP|ssa-name)/io) { return 1; }
548
549  if ($msg =~ /bad\s(data)/io) { return 1; }
550  if ($msg =~ /basic\s(block)/io) { return 1; }
551  if ($msg =~ /not\s(supported)/io) { return 1; }
552  if ($msg =~ /step\s(unknown)/io) { return 1; }
553  if ($msg =~ /original\s(stmt)/io) { return 1; }
554  if ($msg =~ /cycle\s(pattern)/io) { return 1; }
555  if ($msg =~ /determine\s(dependence)/io) { return 1; }
556  if ($msg =~ /consecutive\s(access)/io) { return 1; }
557  if ($msg =~ /vector\s(alignment)/io) { return 1; }
558  if ($msg =~ /clobbers\s(memory)/io) { return 1; }
559  if ($msg =~ /cost.*worth/io) { return 1; }
560  if ($msg =~ /use\s(not)\s(simple)/io) { return 1; }
561  if ($msg =~ /no\s(array)\s(mode)/io) { return 1; }
562
563  if ($msg =~ /(unsupported|unknown|unexpected)\s(pattern)/io) { return 1; }
564
565  if ($msg =~ /interleaved.*(store)/io) { return 1; }
566  if ($msg =~ /vector.*(cost)/io) { return 1; }
567  if ($msg =~ /group.*too\s(large)/io) { return 1; }
568  if ($msg =~ /unary\/binary\/ternary/io) { return 1; }
569
570  return 0;
571}
572
573sub parse_input(\@) {
574  my ($out_r) = @_;
575  my @related = ();
576  my $location_info = undef;
577
578  my @warnout = ();
579  my @errout = ();
580  my @loopnote = (); # contains notes about loop-optimizations (refs to array [file line msg])
581
582  my $did_show_previous = 0;
583  my $is_error          = 0;
584  my $curr_out_r = \@warnout;
585
586 LINE: while (defined($_=<STDIN>)) {
587    chomp;
588    my $filter_current = 0;
589
590    next LINE if $_ eq '';
591
592    if ($_ =~ $reg_file) {
593      my ($file,$line,$msg) = ($1,$2,$');
594
595      if ($msg =~ $reg_is_warning) {
596        my $warn_text = $';
597
598        if ($warn_text =~ $reg_shadow_warning) {
599          if (not $' =~ /this/) { # don't store this warnings (no location follows)
600            store_shadow($_,@warnout);
601            $_ = suppress($_,@warnout, 'shadow-this');
602          }
603          elsif (suppress_shadow_warning_for($file)) {
604            $_ = suppress($_,@warnout, 'shadow');
605            # $location_info = undef;
606          }
607        }
608        elsif ($warn_text =~ $reg_shadow_location) {
609          if (not defined $shadow_warning) { warning('no shadow_warning seen',@warnout); }
610          else {
611            if (suppress_shadow_warning_for($file)) {
612              # don't warn about /usr/include or <built-in> shadowing
613              $_ = suppress($_,@warnout, 'shadowed');
614              @related = ();
615              $location_info = undef;
616            }
617            else {
618              if (defined $location_info) {
619                push @warnout, $location_info;
620                $location_info = undef;
621              }
622              push @warnout, $shadow_warning;
623            }
624            $shadow_warning = undef;
625          }
626        }
627        elsif ($warn_text =~ $reg_unknown_gcc_diagnostic) {
628          # filter warnings about unknown "pragma GCC diagnostic push/pop"
629          die if not defined $compilerVersionNumber;
630          if ($compilerVersionNumber<=447) {
631            $filter_current = 1; # ignore this warning
632          }
633          # otherwise show (affects 4.5.x; 4.6.x accepts push/pop)
634        }
635        else {
636          my $warn_is = Weffpp_warning_wanted($file,$line,$warn_text);
637          if ($warn_is == $UNWANTED) {
638            $filter_current = 1; # ignore this warning
639          }
640          elsif ($warn_is == $WANTED_NO_RELATED) {
641            @related = (); # drop related messages
642          }
643          # rebuild warning (Weffpp_warning_wanted might modify the message)
644          $_ = $file.':'.$line.': warning: '.$warn_text;
645        }
646        $is_error = 0;
647        $curr_out_r = \@warnout;
648      }
649      elsif ($msg =~ $reg_is_error) {
650        $is_error = 1;
651        $curr_out_r = \@errout;
652      }
653      elsif ($msg =~ $reg_is_instantiated) {
654        push @related, $_;
655        $_ = suppress($_,@warnout, 'instanciated');
656      }
657      elsif ($msg =~ $reg_is_required) {
658        push @related, $_;
659        $_ = suppress($_,@warnout, 'required');
660      }
661      elsif ($msg =~ $reg_is_note) {
662        my $note_after = 1; # 0->message follows note; 1->note follows message
663
664        my $note = $';
665        if (is_loopNote($note)==1) {
666          push @loopnote, [ $file, $line, $msg ];
667          $_ = suppress($_,@warnout, 'loop-note');
668        }
669        else {
670          if ($note_after==1) {
671            if ($did_show_previous==0) {
672              if (scalar(@loopnote)>0) {
673                push @loopnote, [ $file, $line, 'ASSUMING_LOOPNOTE [FIXME]: '.$msg ];
674                $_ = suppress($_,@warnout, 'loop-note');
675              }
676              else {
677                $_ = suppress($_,@warnout, 'note-of-nonshown');
678              }
679            }
680            else {
681              if ($msg =~ /in\sexpansion\sof\smacro/o) {
682                drop_last_pushed_relateds(@$curr_out_r);
683              }
684            }
685          }
686          else {
687            # note leads message -> store in related
688            push @related, $_;
689            $_ = suppress($_,@warnout, 'note');
690          }
691        }
692      }
693      elsif ($msg =~ $reg_is_optimizerMsg) { # message from optimized (gcc 9.1++)
694        my $note = $';
695        if (is_loopNote($note)==1) {
696          push @loopnote, [ $file, $line, $msg ];
697          $_ = suppress($_,@warnout, 'loop-note');
698        }
699        else {
700          $_ = suppress($_,@warnout, 'optimizerMsg-of-nonshown');
701        }
702      }
703    }
704    elsif ($_ =~ $reg_location or $_ =~ $reg_location2 or $_ =~ $reg_location3) {
705      $location_info = $_;
706      $_ = suppress($_,@warnout, 'location');
707    }
708    elsif ($_ =~ $reg_inlined_from) {
709      $_ = $2.': note: '.$1;
710      push @related, $_;
711      $_ = suppress($_,@warnout, 'inlined');
712    }
713    elsif ($_ =~ $reg_included) {
714      push @related, included_from_here($1);
715      $_ = suppress($_,@warnout, 'included');
716    }
717    elsif ($_ =~ $reg_clang_dirt) {
718      $_ = undef;
719    }
720    elsif ($_ =~ $reg_file_noline) {
721      if (/^(cc1plus|g\+\+|clang):.*error/o) {
722        ; # display normally
723      }
724      else {
725        # push @related, included_from_here($1);
726        push @related, $_;
727        $_ = suppress($_,@warnout, 'file-level-comment');
728      }
729    }
730    elsif (@related) {
731      if ($_ =~ $reg_included2) {
732        push @related, included_from_here($1);
733        $_ = suppress($_,@warnout, 'included2');
734      }
735    }
736
737    if (defined $_) {
738      if ($filter_current==0) {
739        if ($show_suppressed_lines==1) { warning('passing: '.$_, @warnout); }
740        push_loc_and_related($location_info,$_,@related,@$curr_out_r);
741        $did_show_previous = 1;
742
743        if (($is_error==1) and ($stop_after_first_error==1)) {
744          @warnout = (); # drop warnings
745          last LINE;
746        }
747      }
748      else {
749        die "can't filter errors (Error=$_)" if ($is_error==1);
750        if ($show_filtered_lines==1) { warning('filtered: '.$_, @$curr_out_r); }
751        $did_show_previous = 0;
752      }
753      $location_info = undef;
754      @related = ();
755    }
756  }
757
758  @$out_r = @errout;
759  if ($hide_warnings==0) { push @$out_r, @warnout; }
760
761  if ($dump_loop_optimization or $check_loop_optimization) {
762    # description of vectorization checks available in SOURCE_TOOLS/vectorize.README
763
764    my @loopmsg = ();
765    foreach my $vref (@loopnote) {
766      my ($file,$line,$msg) = @$vref;
767      my $boring = 0;
768      if ($msg =~ /completely\sunrolled/o) { $boring = 1; }
769      if (not $boring) { push @loopmsg, $vref; }
770    }
771
772    # sort messages and count + replace duplicates
773    @loopmsg = sort { compare_located_messages($a,$b); } @loopmsg;
774    {
775      my @undup_loopmsg = ();
776      my $seenDups = 0;
777      push @loopmsg, [ 'x', 0, '' ]; # append sentinel (forces proper counter for last message)
778      foreach (@loopmsg) {
779        my $prev = pop @undup_loopmsg;
780        if (defined $prev) {
781          if (compare_located_messages($prev,$_)!=0) {
782            if ($seenDups>0) { $$prev[2] = $$prev[2].' ['.($seenDups+1).'x]'; } # append counter
783            push @undup_loopmsg, $prev;
784            $seenDups = 0;
785          }
786          else { $seenDups++; }
787        }
788        push @undup_loopmsg, $_;
789      }
790      pop @undup_loopmsg;
791      @loopmsg = @undup_loopmsg;
792    }
793
794    my %loopfiles = map { $$_[0] => 1; } @loopmsg; # list of files for which loop-messages were found
795
796    if ($dump_loop_optimization) {
797      if (scalar(@loopmsg)) {
798        push @$out_r,  "---------------------------------------- dump_loop_optimization";
799        foreach my $vref (@loopmsg) {
800          my ($file,$line,$msg) = @$vref;
801          if ($dump_loop_optimization==1 or is_successfulVectorizationMsg($msg)==1) {
802            push @$out_r, "$file:$line: note: $msg";
803          }
804        }
805        push @$out_r,  "---------------------------------------- dump_loop_optimization [end]";
806        if ((not $check_loop_optimization) and ($REQ_check_loop_optimization==1) and ($dump_loop_optimization != 2)) {
807          my $vref = $loopmsg[0];
808          my $loc = $$vref[0].':'.$$vref[1];
809          push @$out_r,  "$loc: Warning: vectorization checks disabled in this file (need at least one vectorization-comment in ${REQ_checked_file})";
810        }
811      }
812    }
813    if ($check_loop_optimization || ($dump_loop_optimization==2)) {
814      my @comments = ();
815
816      if (defined $checked_file) {
817        grep_loop_comments($checked_file, @comments);
818
819        # read additional comments from included files:
820        delete $loopfiles{$checked_file};
821        foreach (keys %loopfiles) {
822          my @xtra_comments = ();
823          grep_loop_comments($_, @xtra_comments);
824          push @comments, @xtra_comments;
825        }
826      }
827
828      my $dump_comments = 0; # dump comments for debug purposes (should be disabled)
829      if ($dump_loop_optimization and $dump_comments) {
830        if (scalar(@comments)) {
831          push @$out_r,  "---------------------------------------- dump_detected_comments";
832          foreach my $cref (@comments) {
833            my ($file,$line,$msg) = @$cref;
834            push @$out_r, "$file:$line: $msg";
835          }
836          push @$out_r,  "---------------------------------------- dump_detected_comments [end]";
837        }
838      }
839
840      my $errors = 0;
841      foreach my $cref (@comments) {
842        my $loc  = $$cref[0].':'.$$cref[1];
843        my $cmsg = $$cref[2];
844
845        my $was_vectorized          = 0;
846        my $worthless_vectorization = 0;
847        foreach my $vref (@loopmsg) {
848          if (compare_message_location($cref,$vref)==0) {
849            my $vmsg = $$vref[2];
850            if (is_successfulVectorizationMsg($vmsg)==1) {
851              if ($trace_vectorization_success_messages==1) {
852                push @$out_r, "$loc: Note: vectorized message='$vmsg'";
853              }
854              if ($vmsg =~ /\[([0-9]+)x\]/o) { # vectorized multiple times (e.g. in template)
855                $was_vectorized = $1;
856              }
857              else {
858                $was_vectorized = 1;
859              }
860            }
861            elsif (is_notWorthToVectorizeMsg($vmsg)==1) {
862              $worthless_vectorization = 1;
863            }
864          }
865        }
866        if ($cmsg =~ /^LOOP_VECTORIZED/o) {
867          my $rest   = $';
868          my $errmsg = undef;
869
870          # my $expected_vectorizations = compiler_allowed_by($rest,$errmsg); # check for exclusions of specific compiler versions
871          my $expected_vectorizations = parse_expected_vectorizations($rest,$errmsg);
872
873          if (defined $errmsg) {
874            push @$out_r, "$loc: Error: in vectorize-condition: $errmsg";
875            $errors++;
876          }
877          else {
878            my $possibilities  = undef;
879            if (ref $expected_vectorizations eq 'ARRAY') { # multiple vectorization counts will be accepted
880              my $found_matching = undef;
881              foreach my $ev (@$expected_vectorizations) {
882                if ($ev==$was_vectorized) { $found_matching = $ev; }
883              }
884              $possibilities = join('|', @$expected_vectorizations);
885              if (defined $found_matching) {
886                $expected_vectorizations = $found_matching;
887              }
888              else {
889                $expected_vectorizations = 0;
890              }
891            }
892
893            if (not $was_vectorized) {
894              if ($worthless_vectorization==1) {
895                push @$out_r, "$loc: Error: possible but worthless loop vectorization rejected -> use IRRELEVANT_LOOP (compiler version=$compilerVersion)";
896                $errors++;
897              }
898              elsif ((defined $possibilities) or ($expected_vectorizations>0)) {
899                push @$out_r, "$loc: Error: loop vectorization failed (compiler version=$compilerVersion)";
900                $errors++;
901              }
902              # otherwise silently handled like IRRELEVANT_LOOP (meant to handle '=0<cond>')
903            }
904            else {
905              if ($expected_vectorizations==0) { # compiler excluded, but vectorization occurred
906                push @$out_r, "$loc: Error: loop vectorization succeeded $was_vectorized"."x (but compiler version '$compilerVersion' excluded by condition)";
907                $errors++;
908              }
909              elsif ((defined $possibilities) or ($expected_vectorizations>0)) { # check number of vectorizations matches
910                if ($expected_vectorizations!=$was_vectorized) {
911                  my $specified = defined $possibilities ? $possibilities : $expected_vectorizations;
912                  push @$out_r, "$loc: Error: vectorization count mismatch (specified=$specified, found=$was_vectorized)";
913                  $errors++;
914                }
915              }
916            }
917          }
918        }
919      }
920
921      foreach my $vref (@loopmsg) {
922        my $vmsg = $$vref[2];
923        if (is_successfulVectorizationMsg($vmsg)==1) {
924          my $loc  = $$vref[0].':'.$$vref[1];
925          if ($trace_vectorization_success_messages==1) {
926            push @$out_r, "$loc: Note: vectorized message='$vmsg'";
927          }
928          my $has_loop_comment = undef;
929          foreach my $cref (@comments) {
930            if (compare_message_location($cref,$vref)==0) {
931              $has_loop_comment = $$cref[2];
932            }
933          }
934          if (not defined $has_loop_comment) {
935            push @$out_r, "$loc: Warning: Unchecked optimized loop";
936            push @$out_r, "$loc: Note: Comment with LOOP_VECTORIZED to force check";
937            push @$out_r, "$loc: Note: Comment with IRRELEVANT_LOOP to hide this warning";
938          }
939        }
940      }
941      if ($errors) { $exitcode = 1; }
942    }
943  }
944}
945
946sub die_usage($) {
947  my ($err) = @_;
948  print "Usage: postcompile.pl [Options] sourcefile\n";
949  print "Used as compilation output filter for C/C++\n";
950  print "Options:\n";
951  print "    --no-warnings                 hide warnings (plus related messages)\n";
952  print "    --only-first-error            show only first error\n";
953  print "    --original                    pass-through\n";
954  print "    --show-useless-Weff++         do not suppress useless -Weff++ warnings\n";
955  print "    --hide-Noncopyable-advices    do not advice about using Noncopyable\n";
956  print "    --compiler=version            needed for --check-loop-optimization (version e.g. '4.9.1')\n";
957  print "    --dump-loop-optimization      dump (most) notes related to loop vectorization\n";
958  print "    --loop-optimization-candi     show candidates for loop vectorization-check\n";
959  print "    --check-loop-optimization     if sourcefile is listed in \$ARBHOME/SOURCE_TOOLS/vectorized.source,\n";
960  print "                                  => check commented loops have been vectorized\n";
961
962  if (defined $err) {
963    die "Error in postcompile.pl: $err";
964  }
965}
966
967sub set_dump_loop_optimization($) {
968  my ($val) = @_;
969  die if $val==0;
970  if ($dump_loop_optimization==0) {
971    $dump_loop_optimization = $val;
972  }
973  else {
974    die "dump_loop_optimization already set (old=$dump_loop_optimization; new=$val)";
975    # may e.g. happen when using --dump-loop-optimization AND --loop-optimization-candi
976  }
977}
978
979sub main() {
980  my $args = scalar(@ARGV);
981  my $pass_through = 0;
982  my $sourcefile = undef;
983  while ($args>0) {
984    my $arg = shift(@ARGV);
985    if    ($arg eq '--no-warnings') { $hide_warnings = 1; }
986    elsif ($arg eq '--only-first-error') { $stop_after_first_error = 1; }
987    elsif ($arg eq '--original') { $pass_through = 1; }
988    elsif ($arg eq '--show-useless-Weff++') { $filter_Weffpp = 0; }
989    elsif ($arg eq '--hide-Noncopyable-advices') { $filter_Weffpp_copyable = 1; }
990    elsif ($arg eq '--dump-loop-optimization') { set_dump_loop_optimization(1); }
991    elsif ($arg eq '--loop-optimization-candi') { set_dump_loop_optimization(2); }
992    elsif ($arg eq '--check-loop-optimization') { $check_loop_optimization = 1; }
993    elsif ($arg =~ /^--compiler=/o) { $compilerVersion = $'; calcVersionNumber(); }
994    elsif (not defined $sourcefile) { $sourcefile = $arg; }
995    else {
996      die_usage("Unknown argument '$arg'");
997    }
998    $args--;
999  }
1000
1001  defined $sourcefile || die_usage("missing argument 'sourcefile'");
1002  if (not -f $sourcefile) { die "Unknown sourcefile '$sourcefile'"; }
1003
1004  eval {
1005    if ($pass_through==1) {
1006      while (defined($_=<STDIN>)) { print $_; }
1007    }
1008    else {
1009      my @out = ();
1010      detect_needLoopCheck($sourcefile);
1011      parse_input(@out);
1012      store_shadow(undef,@out);
1013      foreach (@out) { print "$_\n"; }
1014    }
1015  };
1016  my $err = $@;
1017  save_from_NC();
1018  if ($err) { die $err; }
1019}
1020main();
1021exit $exitcode;
Note: See TracBrowser for help on using the repository browser.