home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AMIGA PD 1
/
AMIGA-PD-1.iso
/
Programme_zum_Heft
/
Programmieren
/
Kurztests
/
PascalPCQ
/
Examples
/
Peep.p
< prev
next >
Wrap
Text File
|
1991-04-09
|
16KB
|
725 lines
Program Optimizer;
{
Peep.p from PCQ Pascal
Peep is a peephole optimizer that works on the assembly code
produced by PCQ Pascal. It is not designed to work on any other
code, so be careful. It reads in the assembly program, optimizes
whatever it can, then writes out a slightly shorter, slightly
faster equivalent file.
Peep makes all sorts of assumptions about the source code, one of
which is that the source code is correct. For example, if an
instruction takes two operands, Peep expects there to be two
operands. That's O.K. for the compiler output, but you might run
into trouble if you tried using it on normal assembly programs.
It is highly unlikely that anything written in assembly could be
improved by Peep anyway.
Using Peep is entirely optional.
}
{$I "Include:Utils/StringLib.i"}
{$I "Include:Utils/Parameters.i"}
{$I "Include:Utils/Break.i"}
Const
MaxPeeps = 199;
type
Operation = (
op_ADD,
op_ADDA,
op_ADDQ,
op_AND,
op_ASL,
op_ASR,
op_BEQ,
op_BGE,
op_BGT,
op_BLE,
op_BLT,
op_BNE,
op_BPL,
op_BRA,
op_BSET,
op_CLR,
op_CMP,
op_CNOP,
op_DBRA,
op_DC,
op_DIVS,
op_DS,
op_END,
op_EOR,
op_EXG,
op_EXT,
op_JSR,
op_LEA,
op_LINK,
op_LSL,
op_LSR,
op_MOVE,
op_MOVEM,
op_MOVEQ,
op_MULS,
op_NEG,
op_NOT,
op_OR,
op_PEA,
op_RTS,
op_SECTION,
op_SEQ,
op_SGE,
op_SGT,
op_SLE,
op_SLT,
op_SNE,
op_SUB,
op_SUBQ,
op_SWAP,
op_TRAP,
op_TST,
op_UNLK,
op_XDEF,
op_XREF,
op_None,
op_LABEL,
op_EOF);
CodeCell = record
OpCode : Operation;
OSize : Char;
Deleted : Boolean;
Operand1,
Operand2,
Trailer : String;
Buffer : Array [0..127] of Char;
end;
CodeCellPtr = ^CodeCell;
PeepArray = Array [0..MaxPeeps] of CodeCell;
const
OpCodes : Array [op_ADD..op_XREF] of String = (
"add",
"adda",
"addq",
"and",
"asl",
"asr",
"beq",
"bge",
"bgt",
"ble",
"blt",
"bne",
"bpl",
"bra",
"bset",
"clr",
"cmp",
"cnop",
"dbra",
"dc",
"divs",
"ds",
"end",
"eor",
"exg",
"ext",
"jsr",
"lea",
"link",
"lsl",
"lsr",
"move",
"movem",
"moveq",
"muls",
"neg",
"not",
"or",
"pea",
"rts",
"section",
"seq",
"sge",
"sgt",
"sle",
"slt",
"sne",
"sub",
"subq",
"swap",
"trap",
"tst",
"unlk",
"xdef",
"xref");
var
FirstPeep,
LastPeep : Integer;
PeepHole : PeepArray;
InputLine : String;
InputFileName : String;
InputFile : Text;
OutputFileName : String;
OutputFile : Text;
EndOfFile : Boolean;
Changed : Boolean;
Procedure Die(ExitCode : Integer);
begin
Close(InputFile);
Close(OutputFile);
Exit(ExitCode);
end;
Procedure FindOperand(var c : CodeCell; SymText : String);
{
This just does a binary chop search of the list of operations
}
var
top,
middle,
bottom : Operation;
compare : Short;
begin
Bottom := op_ADD;
Top := op_XREF;
compare := strpos(SymText, '.');
if compare = -1 then
c.OSize := ' '
else begin
c.OSize := SymText[Succ(Compare)];
SymText[compare] := '\0';
end;
while Bottom <= Top do begin
middle := Operation((Byte(bottom) + Byte(top)) shr 1);
Compare := stricmp(OpCodes[Middle], SymText);
if Compare = 0 then begin
c.Opcode := Middle;
return;
end else if Compare < 0 then
Bottom := Succ(Middle)
else
Top := Pred(Middle);
end;
Writeln('Unknown instruction "', SymText, '"');
Die(10);
end;
Procedure ReadWord(InLine : String; var pos : Integer;
var dest : String; delim : Char);
begin
while isspace(InLine[pos]) do
Inc(pos);
dest := Adr(Inline[pos]);
while (not isspace(Inline[pos])) and
(Inline[pos] <> '\0') and
(Inline[pos] <> delim) do
Inc(pos);
Inline[pos] := '\0';
Inc(pos);
end;
Procedure ReadInstruction(var c : CodeCell);
var
OpStorage : String;
Leave : Boolean;
InputPos,
LastPos : Integer;
begin
with c do begin
OpCode := op_NONE;
OSize := ' ';
Deleted:= False;
Operand1 := "";
Operand2 := "";
Trailer := "";
InputLine := Adr(c.Buffer);
end;
repeat
Leave := True;
repeat
if eof(InputFile) then begin
c.OpCode := op_EOF;
return;
end;
ReadLn(InputFile, InputLine);
until (strlen(InputLine) > 0) and (InputLine[0] <> '*');
if isspace(InputLine[0]) then begin { It's not a label }
InputPos := 0;
ReadWord(InputLine, InputPos, OpStorage, '\0');
if strlen(OpStorage) > 0 then begin
FindOperand(c, OpStorage);
case c.OpCode of
op_ADD..op_ASR,
op_BSET,op_CMP..op_DBRA,
op_DIVS,op_EOR,op_EXG,
op_LEA..op_MULS,
op_OR, op_SUB, OP_SUBQ :
begin
ReadWord(InputLine, InputPos, c.Operand1, ',');
ReadWord(InputLine, InputPos, c.Operand2, '\0');
end;
op_BEQ..op_BRA,op_CLR,
op_EXT,op_JSR,
op_NEG,op_NOT,op_PEA,
op_SECTION..op_SNE,
op_SWAP..op_UNLK,
op_XDEF,op_XREF :
begin
ReadWord(InputLine, InputPos, c.Operand1, '\0');
end;
op_DC, OP_DS :
begin
while isspace(InputLine[InputPos]) do
Inc(InputPos);
c.Operand1 := Adr(InputLine[Inputpos]);
end;
op_END,op_RTS : ;
end;
end else
Leave := False;
end else { It's a label }
c.OpCode := op_LABEL;
until Leave;
end;
Procedure FillPeepholeArray;
var
WasLabel : Boolean;
begin
LastPeep := 0;
FirstPeep := 0;
repeat
ReadInstruction(PeepHole[LastPeep]);
WasLabel := PeepHole[LastPeep].OpCode = op_LABEL;
Inc(LastPeep);
until WasLabel or (LastPeep > MaxPeeps) or (EOF(InputFile));
end;
Procedure WriteInstruction(CellNum : Integer);
begin
with PeepHole[CellNum] do begin
if OpCode = op_EOF then
return;
if Deleted then
return;
if OpCode = op_LABEL then begin
Writeln(OutputFile, String(Adr(Buffer)));
return;
end;
Write(OutputFile, '\t', OpCodes[OpCode]);
if OSize <> ' ' then
write(OutputFile, '.', OSize);
if strlen(Operand1) > 0 then
Write(OutputFile, '\t', Operand1);
if strlen(Operand2) > 0 then
Write(OutputFile, ',', Operand2);
Writeln(OutputFile);
end;
end;
Procedure EmptyPeepholeArray;
var
i : Integer;
begin
for i := FirstPeep to Pred(LastPeep) do
WriteInstruction(i);
end;
Function NextInstruction(Current : Integer) : Integer;
begin
repeat
Inc(Current);
if Current > LastPeep then
NextInstruction := -1;
until not PeepHole[Current].Deleted;
NextInstruction := Current;
end;
Function IsDataRegister(op : String) : Boolean;
begin
IsDataRegister := (strlen(op) = 2) and
(toupper(op[0]) = 'D') and
isdigit(op[1]);
end;
Function IsAddressRegister(op : String) : Boolean;
begin
IsAddressRegister := ((strlen(op) = 2) and
(toupper(op[0]) = 'A') and
isdigit(op[1])) or
strieq(op, "sp");
end;
Function IsRegister(op : String) : Boolean;
begin
IsRegister := (strlen(op) = 2) and
((toupper(op[0]) = 'A') or (toupper(op[0]) = 'D')) and
isdigit(op[1]);
end;
{
Carry out optimizations in a three-instruction window.
The optimizations are:
scc Dn
tst.b Dn => scc Dn
beq lab b~cc lab
scc Dn
tst.b Dn => scc Dn
bne lab => bcc lab
move.x ??,Dn
any.x ???,Dn => any.x ???,?? not done - sub and add
move.x Dn,?? require one operand to
be a register
beq lab1
bra lab2 => bne lab2 (happens in case statements)
lab1 lab1
}
Procedure Optimize3(Op1 : Integer);
var
Op2, Op3 : Integer;
begin
if Peephole[Op1].Deleted then
return;
Op2 := NextInstruction(Op1);
if Op2 = -1 then
return;
Op3 := NextInstruction(Op2);
if Op3 = -1 then
return;
{ if (Peephole[Op1].OpCode = op_MOVE) and
(Peephole[Op3].OpCode = op_MOVE) and
(Peephole[Op1].OSize = Peephole[Op3].OSize) and
IsDataRegister(Peephole[Op1].Operand2) and
streq(Peephole[Op1].Operand1,Peephole[Op3].Operand2) and
streq(Peephole[Op1].Operand2,Peephole[Op3].Operand1) then begin
case Peephole[Op2].OpCode of
op_ADD..op_ASR,
op_CMP,op_DIVS,
op_EOR,
op_LSL,op_LSR,
op_MULS,op_OR,
op_SUB,op_SUBQ :
if (Peephole[Op2].OSize = Peephole[Op1].OSize) and
streq(Peephole[Op2].Operand2,Peephole[Op1].Operand2) then begin
Peephole[Op2].Operand2 := Peephole[Op1].Operand1;
Peephole[Op1].Deleted := True;
Peephole[Op3].Deleted := True;
Changed := True;
end;
op_CLR,op_NEG,
op_NOT,op_TST :
if (Peephole[Op2].OSize = Peephole[Op1].OSize) and
streq(Peephole[Op2].Operand1,Peephole[Op1].Operand2) then begin
Peephole[Op2].Operand1 := Peephole[Op1].Operand1;
Peephole[Op1].Deleted := True;
Peephole[Op3].Deleted := True;
Changed := True;
end;
end;
end else} if ((Peephole[Op1].OpCode >= op_SEQ) or
(Peephole[Op1].OpCode <= op_SNE)) and
IsDataRegister(Peephole[Op1].Operand1) and
(Peephole[Op2].OpCode = op_TST) and
streq(Peephole[Op1].Operand1, Peephole[Op2].Operand1) and
((Peephole[Op3].OpCode = op_BEQ) or
(Peephole[Op3].OpCode = op_BNE)) then begin
if Peephole[Op3].OpCode = op_BEQ then begin
case Peephole[Op1].OpCode of
op_SEQ : Peephole[Op3].OpCode := op_BNE;
op_SGE : Peephole[Op3].OpCode := op_BLT;
op_SGT : Peephole[Op3].OpCode := op_BLE;
op_SLE : Peephole[Op3].OpCode := op_BGT;
op_SLT : Peephole[Op3].OpCode := op_BGE;
op_SNE : Peephole[Op3].OpCode := op_BEQ;
end;
end else begin
case Peephole[Op1].OpCode of
op_SEQ : Peephole[Op3].OpCode := op_BEQ;
op_SGE : Peephole[Op3].OpCode := op_BGE;
op_SGT : Peephole[Op3].OpCode := op_BGT;
op_SLE : Peephole[Op3].OpCode := op_BLE;
op_SLT : Peephole[Op3].OpCode := op_BLT;
op_SNE : Peephole[Op3].OpCode := op_BNE;
end;
end;
Peephole[Op2].Deleted := True;
Changed := True;
end else if (Peephole[Op1].OpCode = op_BEQ) and
(Peephole[Op2].OpCode = op_BRA) and
(Peephole[Op3].OpCode = op_LABEL) and
streq(Peephole[Op1].Operand1,Adr(Peephole[Op3].Buffer)) then begin
Peephole[Op2].OpCode := op_BNE;
Peephole[Op1].Deleted := True;
Changed := True;
end;
end;
{
Carry out optimizations in a two-instruction window.
The optimizations are:
move.x ??,Dn
move.x Dn,??? => move.x ??,??? (?? <> (a0)+ )
move.x ??,Dn
add.x Dn,??? => add.l ??,???
move.x Dn,???
move.x ???,Dn => move.x Dn,???
move.x Dn,??? move.x Dn,???
move.x ???,?? => move.x Dn,??
any.x ??,Dn
cmp.x #0,Dn => any.x ??,Dn
move.x Dn,??
cmp.x #0,Dn => move.x Dn,?? (?? <> An)
rts
anything => rts
any.x ??,Dn
tst.x Dn => any.x ??,Dn
any.x Dn
tst.x Dn => any.x Dn
move.x ??,Dn => tst.x ??
scc Dn scc Dn
move.b #?,Dn
and.x #255,Dn => move.x #?,Dn
}
Procedure Optimize2(Op1 : Integer);
var
Op2 : Integer;
begin
if Peephole[Op1].deleted then
return;
Op2 := NextInstruction(Op1);
if Op2 = -1 then
return;
if (Peephole[Op1].OpCode = op_MOVE) and
(Peephole[Op2].OpCode = op_MOVE) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
if IsDataRegister(Peephole[Op1].Operand1) and
streq(Peephole[Op1].Operand2,Peephole[Op2].Operand1) then begin
if streq(Peephole[Op1].Operand1,Peephole[Op2].Operand2) then
Peephole[Op2].Deleted := True
else
Peephole[Op2].Operand1 := Peephole[Op1].Operand1;
Changed := True;
end else if IsRegister(Peephole[Op1].Operand2) and
streq(Peephole[Op1].Operand2,Peephole[Op2].Operand1) and
(not streq(Peephole[Op1].Operand1,"(a0)+")) and
(not IsRegister(Peephole[Op2].Operand2)) then begin
Peephole[Op1].Operand2 := Peephole[Op2].Operand2;
Peephole[Op2].Deleted := True;
Changed := True;
end;
end else if Peephole[Op1].OpCode = op_RTS then begin
case Peephole[Op2].OpCode of
op_ADD..op_CMP,
op_DBRA,op_DIVS,
op_EOR..op_RTS,
op_SEQ..op_UNLK : begin
Peephole[Op2].Deleted := True;
Changed := True;
end;
end;
end else if (Peephole[Op2].OpCode = op_CMP) and
(streq(Peephole[Op2].Operand1,"#0") or
streq(Peephole[Op2].Operand1, "#$0")) and
IsDataRegister(Peephole[Op2].Operand2) then begin
case Peephole[Op1].OpCode of
op_NEG,op_NOT,op_EXT :
if streq(Peephole[Op1].Operand1,Peephole[Op2].Operand2) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
Peephole[Op2].Deleted := True;
Changed := True;
end;
op_ADD,op_ADDQ,op_AND,
op_ASL,op_ASR,op_DIVS,op_EOR,
op_EXG,op_LSL,op_LSR,
op_MULS,op_OR,
op_SUB,op_SUBQ :
if streq(Peephole[Op1].Operand2,Peephole[Op2].Operand2) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
Peephole[Op2].Deleted := True;
Changed := True;
end;
op_MOVE, op_MOVEQ :
if streq(Peephole[Op1].Operand2,Peephole[Op2].Operand2) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
Peephole[Op2].Deleted := True;
Changed := True;
end else if streq(Peephole[Op1].Operand1,Peephole[Op2].Operand2) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) and
(not IsAddressRegister(Peephole[Op1].Operand1)) then begin
Peephole[Op2].Deleted := True;
Changed := True;
end;
end;
end else if (Peephole[Op2].OpCode = op_TST) and
IsDataRegister(Peephole[Op2].Operand1) then begin
case Peephole[Op1].OpCode of
op_NEG,op_NOT,op_EXT :
if streq(Peephole[Op1].Operand1,Peephole[Op2].Operand1) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
Peephole[Op2].Deleted := True;
Changed := True;
end;
op_ADD,op_ADDQ,op_AND,
op_ASL,op_ASR,op_DIVS,op_EOR,
op_EXG,op_LSL,op_LSR,
op_MOVE,op_MOVEQ,op_MULS,
op_OR,op_SUB,op_SUBQ :
if streq(Peephole[Op1].Operand2,Peephole[Op2].Operand1) and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
Peephole[Op2].Deleted := True;
Changed := True;
end;
end;
end else if (Peephole[Op1].OpCode = op_MOVE) and
(Peephole[Op2].OpCode >= op_SEQ) and
(Peephole[Op2].OpCode <= op_SNE) and
streq(Peephole[Op1].Operand2,Peephole[Op2].Operand1) then begin
with Peephole[Op1] do begin
OpCode := op_TST;
Operand2 := "";
end;
Changed := True;
end else if (Peephole[Op1].OpCode = op_MOVE) and
(Peephole[Op1].Operand1[0] = '#') and
(Peephole[Op2].OpCode = op_AND) and
streq(Peephole[Op2].Operand1,"#255") and
IsDataRegister(Peephole[Op1].Operand2) and
streq(Peephole[Op1].Operand2,Peephole[Op2].Operand2) and
(Peephole[Op1].OSize = 'b') then begin
Peephole[Op1].OSize := Peephole[Op2].OSize;
Peephole[Op2].Deleted := True;
Changed := True;
{ end else if (Peephole[Op1].OpCode = op_MOVE) and
(Peephole[Op2].OpCode = op_CMP) and
IsDataRegister(Peephole[Op1].Operand2) and
streq(Peephole[Op1].Operand2,Peephole[Op2].Operand2) and
(Peephole[Op2].Operand1[0] = '#') and
(Peephole[Op1].OSize = Peephole[Op2].OSize) then begin
Peephole[Op2].Operand2 := Peephole[Op1].Operand1;
Peephole[Op1].Deleted := True;
Changed := True; }
end;
end;
{
Carry out optimizations in a one-instruction window.
The optimizations are:
move.x #0,?? => clr.x ?? (if x <> l and ?? <> Dn )
}
Procedure Optimize1(Op : Integer);
begin
if Peephole[Op].Deleted then
return;
with Peephole[Op] do begin
if (OpCode = op_MOVE) and
(streq(Operand1, "#0") or streq(Operand1, "#$0")) and
((not IsDataRegister(Operand2)) or (OSize <> 'l')) then begin
Operand1 := Operand2;
Operand2 := "";
OpCode := op_CLR;
Changed := True;
end;
end;
end;
var
i : Integer;
begin
Writeln('PCQ Peephole optimizer');
InputFileName := AllocString(256);
OutputFileName := AllocString(256);
GetParam(1,InputFileName);
GetParam(2,OutputFileName);
if (strlen(InputfileName) <= 0) or
(strlen(OutputFileName) <= 0) then begin
Writeln('Usage: Optimize filename');
Exit(20);
end;
FirstPeep := 0;
LastPeep := 0;
if not open(OutputFileName, OutputFile) then begin
Writeln('Could not open output file: ', OutputFileName);
Exit(10);
end;
if reopen(InputFileName, InputFile) then begin
while not eof(InputFile) do begin
FillPeepholeArray;
repeat
Changed := False;
for i := FirstPeep to LastPeep do begin
Optimize3(i);
Optimize2(i);
Optimize1(i);
end;
if CheckBreak then
Die(20);
until not Changed;
EmptyPeepholeArray;
end;
Die(0);
end;
end.