uae-wii/src/md-68k/cpuopti
2009-05-05 15:36:48 +00:00

295 lines
10 KiB
Perl

#!/bin/perl
#
# Usage: $0 <cpu?.s
#
# Small perl script to optimise cpu?.s
# Note: some optimisations done here are not safe! It is a chance
# if everything works fine...
#
# 05/04/97: Modified to make it work with perl5.
# 25/10/97: Removed some optimisations suspected to introduce bugs.
#
# (c) By Samuel Devulder, 04/97.
#
# uncomment the next 2 lines if you experience problems with the
# optimized code:
#while(<>) { print; }
#exit 0;
###############################################################################
if($#ARGV >= $[) {
&usage;
}
###############################################################################
while(<>) {
print;
last if /^_op_[0-9a-f_]+:$/;
}
###############################################################################
chop;
print STDERR "$_\r";
$num_opt = 0;
while($last_func = &analyse_function) {
while(&optimize_function) {}
&dump_function;
print $last_func;$_ = $last_func;chop;
print STDERR "$_ ($num_opt) \r";
}
while(&optimize_function) {}
&dump_function;
print STDERR "$num_opt optimisations \n";
exit 0;
###############################################################################
sub delete_line {
local($i) = @_;
for(; $i < $lineno; ++$i) {
$line[$i] = $line[1+$i];
}
$line[--$lineno] = "";
}
###############################################################################
sub optimize_function {
local($i, $j, $ext, $adr, $reg, $opt, $tmp);
$opt = $num_opt;
for($i = 0; $i < $lineno; ++$i) {
study($line[$i]);
#################################################################
# INST.x X,Dn => INST.x X,Dn
# TST.x Dn <deleted>
#################################################################
if(($line[$i] =~/(mov[e]?|or|and|add|sub|tst)([bwl])\s+.+,(d[0-7])$/)
&& ($line[$i+1]=~ /tst$2\s+$3/)) {
&delete_line($i+1);
++$num_opt;
}
#################################################################
# MOVE.x Dn,X => MOVE.x Dn,X
# TST.x Dn <deleted>
#################################################################
if(($line[$i] =~ /mov[e]?([bwl])\s+(d[0-7]),(.+)$/)
&& ($line[$i+1]=~ /tst$1\s+$2/)) {
&delete_line($i+1);
++$num_opt;
}
#################################################################
# MOVE.B 1(An),Dr => MOVE.W (An)+,Dr
# ADDQ.x #2,AN <deleted>
# This is allowed since An always points on (B1,B2) With B1==0
#################################################################
if($line[$i] =~ /moveb\s+(a[0-7])@\(1\),(d[0-7])$/) {
$adr=$1; $reg=$2;
if($line[$i+1] =~ /addq.\s+#2,$adr/) {
$line[$i] = "\tmovew $adr@+,$reg\n";
&delete_line($i+1);
++$num_opt;
#################################################################
# CLR.W Dn => <deleted>
# MOVE.W X,Dn MOVE.W X,Dn
#################################################################
if(($i>1) && ($line[$i-1] =~ /clrw\s+$reg/)) {
&delete_line($i-1);
++$num_opt;
}
}
}
#################################################################
# TST.x Dn => MOVE.x Dn,X
# ..(Dn not used).. ..(Dn not used)..
# MOVE.x Dn,X <deleted>
#################################################################
# if(($line[$i] =~ /tst([bwl])\s+(d[0-7])$/)) {
# $ext = $1; $reg = $2;
# $line[$lineno] = "rts"; # sentinel
# $tmp = "(^.+:)|rts|\sj.+\s|$reg";
# for($j = $i+1; $line[$j] !~ /$tmp/; ++$j) {}
# if($line[$j] =~ /mov[e]?$ext\s+$reg,(.+)$/) {
# $adr = $1;
# $tmp = "";
# if($adr =~ /(a[0-7])/) {if($tmp eq "") {$tmp = "$1";} else {$tmp = "$tmp|$1"}}
# if($adr =~ /(d[0-7])/) {if($tmp eq "") {$tmp = "$1";} else {$tmp = "$tmp|$1"}}
# if(!($tmp eq "")) {
# for($k = $i+1; $k<$j && ($line[$k]!~/$tmp/); ++$k) {}
# } else {$k = $j;}
# if($k == $j) {
# $line[$i] = $line[$j];
# &delete_line($j);
# ++$num_opt;
# }
# }
# }
if($line[$i] =~ /_regs/) { # some speedup
#################################################################
# INST .._regs+N1.. => lea _regs+N2,An
# ..(no refs to _regs).. INST ..N1-N2(An)..
# lea _regs+N2,An ..(no refs to _regs)..
#################################################################
if($line[$i] =~ /_regs(\+\d+)?/) {
$N1 = $1;
$line[$lineno] = "rts"; # sentinel
$tmp = "_regs|rts|\s+j.+\s|(^.+:)";
for($j = $i+1; $line[$j] !~ /$tmp/; ++$j) {}
if($line[$j] =~ /lea\s+_regs(\+\d+)?,(a[0-7])$/) {
$N2 = $1; $An = $2;
for($k = $i; $line[$k] !~ /$An/; $k++) {}
if($k == $j) {
$N1 =~ s/^\+//; $N2 =~ y/+/-/;
if($N1 + $N2) {
$line[$i] =~ s/_regs(\+?)$N1/$An@\($N1$N2\)/g;
} else {
$line[$i] =~ s/_regs(\+?)$N1/$An@/g;
}
$ext = $line[$j];
for($k=$j; $k>$i; --$k) {$line[$k] = $line[$k-1];}
$line[$i] = $ext;
++$num_opt;
}
}
}
#################################################################
# LEA _regs+N1,An => LEA _regs+N1,An
# ..An not modified.. ...
# INST .._regs+N2.. INST ..(N2-N1)An..
#################################################################
if($line[$i] =~ /lea\s+_regs(\+\d+)?,(a[0-7])/) {
$N1 = $1;$An = $2;
$line[$lineno] = "rts"; # sentinel
$tmp = "_regs|$An@[-+]|,$An|\sj.+\s|rts|(^.+:)";
for($j = $i+1; $line[$j] !~ /$tmp/; ++$j) {}
if($line[$j] =~ /_regs(\+\d+)?/) {
$N2 = $1; $N1 =~ y/+/-/;
$tmp = $N2; $tmp =~ s/[+]/\\+/;
if($N1 + $N2) {
$line[$j] =~ s/_regs$tmp/$An@\($N2$N1\)/g;
} else {
$line[$j] =~ s/_regs$tmp/$An@/g;
}
$line[$j] =~ s/\(\)//g;
++$num_opt;
}
}
}
#################################################################
# MOVE.x X,Dp => MOVE.x X,Dp
# ..Dp not used.. MOVE.W CCR,Y
# TST.x Dp ..Dp not used..
# MOVE.W ccr,Y
#################################################################
# if($line[$i] =~ /mov[e]?([bwl])\s+.+,(d[0-7])$/) {
# $ext = $1;$reg = $2;
# $line[$lineno] = "rts"; # sentinel
# $tmp = "$reg|rts|\sj.+\s|(^.+:)";
# for($j = $i+1; $line[$j] !~ /$tmp/; $j++) {}
# if(($line[$j] =~ /tst$ext\s+$reg$/)
# && ($line[$j+1] =~ /mov[e]?w\s+ccr,/)) {
# &delete_line($j);
# $ext = $line[$j];
# for($k=$j;$k>$i+1;--$k) {$line[$k] = $line[$k-1];}
# $line[$i+1] = $ext;
# ++$num_opt;
# }
# }
#################################################################
# General instruction scheduling optimisation:
# INST1 <memory op> => INST1 <memory op>
# INST2 <memory op> INST3 [R1,]R2
# INST3 [R1,]R2 INST2 <memory op>
#################################################################
if(($i>=2)
&& ($line[$i] =~ /\s+(([ad][0-7]),)?([ad][0-7])$/)
&& ($line[$i] !~ /^.+:/)
&& ($line[$i+1] !~ /ccr|jb[^s]/)) {
$adr = $2?$2:"a8"; # unused register
$reg = $3;
study($line[$i-1]);
study($line[$i-2]);
if(($line[$i-1] =~ /@|_regflags/)
&& ($line[$i-2] =~ /@|_regflags/)
&& ($line[$i-1] !~ /(^[^\s]+:)|$adr|$reg|jb|ccr|lea|pea/)
&& ($line[$i-2] !~ /$adr|$reg|lea|pea/)) {
$tmp = $line[$i-1];
$line[$i-1] = $line[$i];
$line[$i] = $tmp;
++$num_opt;
}
}
}
return $num_opt-$opt;
}
###############################################################################
sub not_used {
local($i, $reg) = @_;
while($i < $lineno) {
$line[$i]=~/$reg/ && return 0;
++$i;
}
return 1;
}
###############################################################################
sub not_used_before {
local($i, $reg) = @_;
while($i--) {
$line[$i]=~/$reg/ && return 0;
}
return 1;
}
###############################################################################
sub analyse_function {
$lineno = 0;
while(<>) {
next if /^#(NO_)?APP/;
last if /^_op_[0-9a-f_]+:$/;
$line[$lineno++] = $_;
}
return $_;
}
###############################################################################
sub dump_function {
local($i);
for($i=0;$i < $lineno; ++$i) {
$_ = $line[$i];
s/lea\s(a[0-7])\@\(\),/movel $1,/;
print;
}
}
###############################################################################
sub usage {
open(FILE,__FILE__);
open(OUT,"|less");
<FILE>;
while(<FILE>) {
last if !/^#/;
s/^#[ ]?//;
s/\$0/$0/;
print OUT;
}
close OUT;
exit;
}
###############################################################################