mirror of
https://github.com/Oibaf66/uae-wii.git
synced 2024-06-03 00:58:47 +02:00
295 lines
10 KiB
Perl
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;
|
|
}
|
|
|
|
###############################################################################
|
|
|