#!/usr/bin/perl

$lst=shift(@ARGV).'.lst';
$mhzd=135;
$mhz=shift(@ARGV) || $mhzd;

($mhz =~ /^\d+(\.\d*){0,1}$/) && (-f $lst) || die "
Usage:

$0 base [mhz]

base.lst is a .lst file created with 'xlf -qlist'
mhz is the CPU-speed (default $mhzd)
$0
will give a summary of instructions, cycles and flops
for most loops, starting with label CL.n and
with a branch instruction back to CL.n

Written 25/11-96 by Lars Kr. Lundin - lkl\@imm.dtu.dk

";

# The number of flops per instruction
#  - Some instructions may need to be added
%f=('fma',2
   ,'fms',2
   ,'fnma',2
   ,'fnms',2
   ,'fa',1
   ,'fs',1
   ,'fm',1
   ,'fd',1);

unless ($noio) {
  print "\n";
  print "Loop-summary of instructions, cycles and flops in $lst\n";
  print "\n";
}

# This list does not need to be complete,
# - but the instructions in the list will appear in that order in the summary
$inst = 'fma|fnma|fms|fnms|fa|fs|fm|fd|fmr';
$inst.='|lfq|lfqu|lfd|lfdu|lfdx||lfs|lm|l|stfq|stfqu|stfd|stfdu|st';

($hfl,$tcyc,$tfl,$tld,$tst)=&qlist($lst,$mhz,$noio);

sub qlist {
    local($lst,$mhz,$noio)=@_;

  local(@nlabel,$hfl,%ns);

  $nlabel=-1;

  # Get object listing
  open(IN,$lst);
  @obl=grep(/^\s+\d*\|/,<IN>);
  close(IN);

  for (@obl) {
    /\s+CL\.(\d+):/ && ($ns{$1}=1);
    /CL\.(\d+),/ && $ns{$1} && push(@nlabel,$1) && undef($ns{$1});
  }

for $nlabel (@nlabel) {

  for (@obl) {
    # Check for new object
    /\bPDEF\s+(\S+)/ && ($obj=$1);

    if ($inside && /^\s+\d+\|\s+[0-9A-F]+\s(\w+)\s+[0-9A-F]+\s+(\d+)/) {
      $ninst{$1}++;
      $ncyc{$1}+=$2;
      $1 =~ /^($inst)$/ || ($inst.="|$1");

      # Check if the loop is ending
      /CL\.$nlabel,/ && last;
    }

    # Find the loop
    /\s+CL\.$nlabel\:/ && ($inside=1);
  }
  if ($inside) {
    ($mfl,$tcyc,$tfl,$tld,$tst) = &pr_loop($obj,$nlabel);
    $hfl = $mfl if ($mfl > $hfl);
  }
#  print join("\n",split(/\|/,$inst));
  undef @loop;
  undef $inside;
  undef %ninst;
  undef %ncyc;
  undef $obj;
};

($hfl,$tcyc,$tfl,$tld,$tst);
}

sub pr_loop {

# Print loop summary

local($obj,$nlabel)=@_;

unless ($noio) {
  print "-------------------------------------\n\n";
  print "Loop CL.$nlabel in object $obj \n";
  printf("           no.    cyc.   cyc.\n");
  printf("Instr.     of     spent  lost  flops\n");
}

local($mfl,$tinst,$tcyc,$tfl,$tlost,$tst,$tld);

foreach $i (split(/\|/,$inst)) {
  $tinst+=$ninst{$i};
  $tcyc +=$ncyc{$i};
  $fl    =$f{$i}*$ninst{$i};;
  $tfl  +=$fl;

  $lost=$ncyc{$i}-int($f{$i}*$ninst{$i}/4);
  $tlost+=$lost;
  $tld+=$ninst{$i} if ($i =~ /^l/);
  $tst+=$ninst{$i} if ($i =~ /^st/);

  if ($ninst{$i} && !$noio) {
    printf("%-6s  %5lu  %5lu  %5ld    %5lu\n",$i,$ninst{$i},$ncyc{$i},$lost,$fl);
  }

}
$mfl=0;
$eff=0;
if ($tcyc >0) {
  $mfl=$mhz*$tfl/$tcyc;
  $eff=25*$tfl/$tcyc;
};

unless ($noio) {
  print "------   ----  -----  -----    -----  MFLOP/s  %-eff.  Ld's  St's\n";
  printf("Total   %5lu" .  "  %5lu". "  %5ld". "  %7lu " . " %7.2lf  %4.1lf   %3lu   %3lu\n"
    ,$tinst,$tcyc,$tlost,$tfl,$mfl,$eff,$tld,$tst);
  print "\n";
}
($mfl,$tcyc,$tfl,$tld,$tst);
}