#!/bin/perl # # Usage: $0 ) { 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 ################################################################# 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 ################################################################# 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 # 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 => # 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 ################################################################# # 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 => INST1 # INST2 INST3 [R1,]R2 # INST3 [R1,]R2 INST2 ################################################################# 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"); ; while() { last if !/^#/; s/^#[ ]?//; s/\$0/$0/; print OUT; } close OUT; exit; } ###############################################################################