mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-20 15:49:22 +02:00
* fixed generic optimizer
* enabled generic optimizer for sparc
This commit is contained in:
parent
86f78c7300
commit
e04b172854
@ -1,6 +1,6 @@
|
||||
{
|
||||
$Id$
|
||||
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
|
||||
Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This unit contains the interface routines between the code generator
|
||||
@ -24,67 +24,73 @@
|
||||
}
|
||||
Unit aopt;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
Interface
|
||||
|
||||
Uses Aasmbase,aasmtai,aasmcpu, cobjects, aoptobj, aoptcpud, aoptcpub {aoptcs, aoptpeep} ;
|
||||
Uses
|
||||
aasmbase,aasmtai,aasmcpu,
|
||||
aoptobj;
|
||||
|
||||
Type
|
||||
PAsmOptimizer = ^TAsmOptimizer;
|
||||
TAsmOptimizer = Object(TAoptObj)
|
||||
TAsmOptimizer = class(TAoptObj)
|
||||
|
||||
{ _AsmL is the PAasmOutpout list that has to be optimized }
|
||||
Constructor Init(_AsmL: PAasmOutput);
|
||||
Constructor create(_AsmL: taasmoutput);
|
||||
|
||||
{ call the necessary optimizer procedures }
|
||||
Procedure Optimize;
|
||||
Destructor Done;
|
||||
Destructor destroy;override;
|
||||
|
||||
private
|
||||
|
||||
Function FindLoHiLabels: Pai;
|
||||
Function FindLoHiLabels: tai;
|
||||
Procedure BuildLabelTableAndFixRegAlloc;
|
||||
|
||||
End;
|
||||
|
||||
procedure Optimize(AsmL:Paasmoutput);
|
||||
var
|
||||
casmoptimizer : class of tasmoptimizer;
|
||||
|
||||
procedure Optimize(AsmL:taasmoutput);
|
||||
|
||||
Implementation
|
||||
|
||||
uses cpuinfo, globtype, globals;
|
||||
uses
|
||||
cpuinfo, globtype, globals,
|
||||
aoptda,aoptcpu,aoptcpud;
|
||||
|
||||
Constructor TAsmOptimizer.Init(_AsmL: PAasmOutput);
|
||||
Constructor TAsmOptimizer.create(_AsmL: taasmoutput);
|
||||
Begin
|
||||
AsmL := _AsmL;
|
||||
inherited create(_asml,nil,nil,nil);
|
||||
{setup labeltable, always necessary}
|
||||
New(LabelInfo);
|
||||
LabelInfo^.LowLabel := High(AWord);
|
||||
LabelInfo^.HighLabel := 0;
|
||||
LabelInfo^.LabelDif := 0;
|
||||
LabelInfo^.LabelTable:=nil;
|
||||
End;
|
||||
|
||||
Function TAsmOptimizer.FindLoHiLabels: Pai;
|
||||
Function TAsmOptimizer.FindLoHiLabels: tai;
|
||||
{ Walks through the paasmlist to find the lowest and highest label number. }
|
||||
{ Returns the last Pai object of the current block }
|
||||
Var LabelFound: Boolean;
|
||||
P: Pai;
|
||||
p: tai;
|
||||
Begin
|
||||
LabelFound := False;
|
||||
P := BlockStart;
|
||||
With LabelInfo^ Do
|
||||
Begin
|
||||
While Assigned(P) And
|
||||
((P^.typ <> Ait_Marker) Or
|
||||
(Pai_Marker(P)^.Kind <> AsmBlockStart)) Do
|
||||
((P.typ <> Ait_Marker) Or
|
||||
(tai_Marker(P).Kind <> AsmBlockStart)) Do
|
||||
Begin
|
||||
If (Pai(p)^.typ = ait_label) Then
|
||||
If (Pai_Label(p)^.l^.is_used) Then
|
||||
If (p.typ = ait_label) Then
|
||||
If (tai_Label(p).l.is_used) Then
|
||||
Begin
|
||||
LabelFound := True;
|
||||
If (Pai_Label(p)^.l^.labelnr < LowLabel) Then
|
||||
LowLabel := Pai_Label(p)^.l^.labelnr;
|
||||
If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
|
||||
HighLabel := Pai_Label(p)^.l^.labelnr
|
||||
If (tai_Label(p).l.labelnr < LowLabel) Then
|
||||
LowLabel := tai_Label(p).l.labelnr;
|
||||
If (tai_Label(p).l.labelnr > HighLabel) Then
|
||||
HighLabel := tai_Label(p).l.labelnr
|
||||
End;
|
||||
GetNextInstruction(p, p)
|
||||
End;
|
||||
@ -96,9 +102,9 @@ Begin
|
||||
End;
|
||||
|
||||
Procedure TAsmOptimizer.BuildLabelTableAndFixRegAlloc;
|
||||
{ Builds a table with the locations of the labels in the paasmoutput. }
|
||||
{ Builds a table with the locations of the labels in the taasmoutput. }
|
||||
{ Also fixes some RegDeallocs like "# %eax released; push (%eax)" }
|
||||
Var p, hp1, hp2: Pai;
|
||||
Var p, hp1, hp2: tai;
|
||||
UsedRegs: TRegSet;
|
||||
Begin
|
||||
UsedRegs := [];
|
||||
@ -110,79 +116,82 @@ Begin
|
||||
p := BlockStart;
|
||||
While (P <> BlockEnd) Do
|
||||
Begin
|
||||
Case p^.typ Of
|
||||
Case p.typ Of
|
||||
ait_Label:
|
||||
If Pai_Label(p)^.l^.is_used Then
|
||||
LabelTable^[Pai_Label(p)^.l^.labelnr-LowLabel].PaiObj := p;
|
||||
If tai_label(p).l.is_used Then
|
||||
LabelTable^[tai_label(p).l.labelnr-LowLabel].PaiObj := p;
|
||||
ait_regAlloc:
|
||||
begin
|
||||
if PairegAlloc(p)^.Allocation then
|
||||
{!!!!!!!!!
|
||||
if tai_regalloc(p).ratype=ra_alloc then
|
||||
Begin
|
||||
If Not(PaiRegAlloc(p)^.Reg in UsedRegs) Then
|
||||
UsedRegs := UsedRegs + [PaiRegAlloc(p)^.Reg]
|
||||
If Not(tai_regalloc(p).Reg in UsedRegs) Then
|
||||
UsedRegs := UsedRegs + [tai_regalloc(p).Reg]
|
||||
Else
|
||||
Begin
|
||||
hp1 := p;
|
||||
hp2 := nil;
|
||||
While GetLastInstruction(hp1, hp1) And
|
||||
Not(RegInInstruction(PaiRegAlloc(p)^.Reg, hp1)) Do
|
||||
Not(RegInInstruction(tai_regalloc(p).Reg, hp1)) Do
|
||||
hp2:=hp1;
|
||||
If hp2<>nil Then
|
||||
Begin
|
||||
hp1 := New(PaiRegAlloc, DeAlloc(PaiRegAlloc(p)^.Reg));
|
||||
InsertLLItem(Pai(hp2^.previous), hp2, hp1);
|
||||
hp1:=tai_regalloc.DeAlloc(tai_regalloc(p).Reg,hp2);
|
||||
InsertLLItem(tai(hp2.previous), hp2, hp1);
|
||||
End;
|
||||
End;
|
||||
End
|
||||
else
|
||||
Begin
|
||||
UsedRegs := UsedRegs - [PaiRegAlloc(p)^.Reg];
|
||||
UsedRegs := UsedRegs - [tai_regalloc(p).Reg];
|
||||
hp1 := p;
|
||||
hp2 := nil;
|
||||
While Not(FindRegAlloc(PaiRegAlloc(p)^.Reg, Pai(hp1^.Next))) And
|
||||
While Not(FindRegAlloc(tai_regalloc(p).Reg, tai(hp1.Next))) And
|
||||
GetNextInstruction(hp1, hp1) And
|
||||
RegInInstruction(PaiRegAlloc(p)^.Reg, hp1) Do
|
||||
RegInInstruction(tai_regalloc(p).Reg, hp1) Do
|
||||
hp2 := hp1;
|
||||
If hp2 <> nil Then
|
||||
Begin
|
||||
hp1 := Pai(p^.previous);
|
||||
AsmL^.Remove(p);
|
||||
InsertLLItem(hp2, Pai(hp2^.Next), p);
|
||||
hp1 := tai(p.previous);
|
||||
AsmL.Remove(p);
|
||||
InsertLLItem(hp2, tai(hp2.Next), p);
|
||||
p := hp1;
|
||||
End
|
||||
End
|
||||
};
|
||||
End
|
||||
End
|
||||
End;
|
||||
P := Pai(p^.Next);
|
||||
P := tai(p.Next);
|
||||
While Assigned(p) And
|
||||
(p^.typ in (SkipInstr - [ait_regalloc])) Do
|
||||
P := Pai(P^.Next)
|
||||
(p.typ in (SkipInstr - [ait_regalloc])) Do
|
||||
P := tai(P.Next)
|
||||
End
|
||||
End;
|
||||
|
||||
|
||||
|
||||
Procedure TAsmOptimizer.Optimize;
|
||||
Var HP: Pai;
|
||||
DFA: PAOptDFACpu;
|
||||
Var
|
||||
HP: tai;
|
||||
pass: longint;
|
||||
Begin
|
||||
BlockStart := Pai(AsmL^.First);
|
||||
pass:=0;
|
||||
BlockStart := tai(AsmL.First);
|
||||
While Assigned(BlockStart) Do
|
||||
Begin
|
||||
{ Initialize BlockEnd and the LabelInfo (low and high label) }
|
||||
BlockEnd := FindLoHiLabels;
|
||||
{ initialize the LabelInfo (labeltable) and fix the regalloc info }
|
||||
BuildLabelTableAndFixRegAlloc;
|
||||
{ peephole optimizations, twice because you can't do them all in one }
|
||||
{ pass }
|
||||
{ PeepHoleOptPass1;
|
||||
PeepHoleOptPass1;}
|
||||
if pass = 0 then
|
||||
PrePeepHoleOpts;
|
||||
{ Peephole optimizations }
|
||||
PeepHoleOptPass1;
|
||||
{ Only perform them twice in the first pass }
|
||||
if pass = 0 then
|
||||
PeepHoleOptPass1;
|
||||
If (cs_slowoptimize in aktglobalswitches) Then
|
||||
Begin
|
||||
New(DFA,Init(AsmL,BlockStart,BlockEnd,LabelInfo));
|
||||
// DFA:=TAOptDFACpu.Create(AsmL,BlockStart,BlockEnd,LabelInfo);
|
||||
{ data flow analyzer }
|
||||
DFA^.DoDFA;
|
||||
DFA.DoDFA;
|
||||
{ common subexpression elimination }
|
||||
{ CSE;}
|
||||
End;
|
||||
@ -198,17 +207,17 @@ Begin
|
||||
{ assembler block or nil}
|
||||
BlockStart := BlockEnd;
|
||||
While Assigned(BlockStart) And
|
||||
(BlockStart^.typ = ait_Marker) And
|
||||
(Pai_Marker(BlockStart)^.Kind = AsmBlockStart) Do
|
||||
(BlockStart.typ = ait_Marker) And
|
||||
(tai_Marker(BlockStart).Kind = AsmBlockStart) Do
|
||||
Begin
|
||||
{ we stopped at an assembler block, so skip it }
|
||||
While GetNextInstruction(BlockStart, BlockStart) And
|
||||
((BlockStart^.Typ <> Ait_Marker) Or
|
||||
(Pai_Marker(Blockstart)^.Kind <> AsmBlockEnd)) Do;
|
||||
{ blockstart now contains a pai_marker(asmblockend) }
|
||||
((BlockStart.Typ <> Ait_Marker) Or
|
||||
(tai_Marker(Blockstart).Kind <> AsmBlockEnd)) Do;
|
||||
{ blockstart now contains a tai_marker(asmblockend) }
|
||||
If Not(GetNextInstruction(BlockStart, HP) And
|
||||
((HP^.typ <> ait_Marker) Or
|
||||
(Pai_Marker(HP)^.Kind <> AsmBlockStart)
|
||||
((HP.typ <> ait_Marker) Or
|
||||
(tai_Marker(HP).Kind <> AsmBlockStart)
|
||||
)
|
||||
) Then
|
||||
{skip the next assembler block }
|
||||
@ -219,29 +228,34 @@ Begin
|
||||
End;
|
||||
End;
|
||||
|
||||
Destructor TAsmOptimizer.Done;
|
||||
Destructor TAsmOptimizer.Destroy;
|
||||
Begin
|
||||
Dispose(LabelInfo)
|
||||
End;
|
||||
|
||||
|
||||
procedure Optimize(AsmL:Paasmoutput);
|
||||
procedure Optimize(AsmL:taasmoutput);
|
||||
var
|
||||
p : PAsmOptimizer;
|
||||
p : TAsmOptimizer;
|
||||
begin
|
||||
new(p,Init(AsmL));
|
||||
p^.Optimize;
|
||||
dispose(p,Done);
|
||||
p:=casmoptimizer.Create(AsmL);
|
||||
p.Optimize;
|
||||
p.free
|
||||
end;
|
||||
|
||||
|
||||
End.
|
||||
begin
|
||||
casmoptimizer:=TAsmOptimizer;
|
||||
end.
|
||||
|
||||
{Virtual methods, most have to be overridden by processor dependent methods}
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.6 2004-06-20 08:55:28 florian
|
||||
* logs truncated
|
||||
Revision 1.7 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.6 2004/06/20 08:55:28 florian
|
||||
* logs truncated
|
||||
}
|
||||
|
@ -23,23 +23,29 @@
|
||||
}
|
||||
unit aoptbase;
|
||||
|
||||
Interface
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
uses aasmbase,aasmcpu,aasmtai,
|
||||
cpubase;
|
||||
interface
|
||||
|
||||
{ the number of tai objects processed by an optimizer object since the last }
|
||||
{ time a register was modified }
|
||||
Type TInstrSinceLastMod = Array[LoGPReg..HiGPReg] of byte;
|
||||
uses
|
||||
aasmbase,aasmcpu,aasmtai,
|
||||
cpubase,
|
||||
cgbase;
|
||||
|
||||
Type
|
||||
{ the number of tai objects processed by an optimizer object since the last
|
||||
time a register was modified }
|
||||
{ size at each dimension depends on the registers of this type }
|
||||
TInstrSinceLastMod = Array[tregistertype] of pbyte;
|
||||
|
||||
{ the TAopBase object implements the basic methods that most other }
|
||||
{ assembler optimizer objects require }
|
||||
Type
|
||||
TAoptBase = Object
|
||||
TAoptBase = class
|
||||
{ processor independent methods }
|
||||
|
||||
constructor init;
|
||||
destructor done;
|
||||
constructor create;
|
||||
destructor destroy;override;
|
||||
{ returns true if register Reg is used by instruction p1 }
|
||||
Function RegInInstruction(Reg: TRegister; p1: tai): Boolean;
|
||||
{ returns true if register Reg occurs in operand op }
|
||||
@ -83,39 +89,24 @@ Type
|
||||
|
||||
end;
|
||||
|
||||
Function RefsEqual(Const R1, R2: TReference): Boolean;
|
||||
|
||||
implementation
|
||||
|
||||
Implementation
|
||||
uses
|
||||
globtype,globals, aoptcpub, cpuinfo;
|
||||
|
||||
uses globals, aoptcpub, cpuinfo;
|
||||
|
||||
Function RefsEqual(Const R1, R2: TReference): Boolean;
|
||||
Begin
|
||||
RefsEqual := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup)
|
||||
And (R1.Base = R2.Base)
|
||||
{$ifdef RefsHaveindex}
|
||||
And (R1.Index = R2.Index)
|
||||
{$endif RefsHaveindex}
|
||||
{$ifdef RefsHaveScale}
|
||||
And (R1.ScaleFactor = R2.ScaleFactor)
|
||||
{$endif RefsHaveScale}
|
||||
And (R1.Symbol = R2.Symbol)
|
||||
{$ifdef RefsHaveSegment}
|
||||
And (R1.Segment = R2.Segment)
|
||||
{$endif RefsHaveSegment}
|
||||
;
|
||||
End;
|
||||
|
||||
|
||||
constructor taoptbase.init;
|
||||
constructor taoptbase.create;
|
||||
begin
|
||||
inherited create;
|
||||
end;
|
||||
|
||||
destructor taoptbase.done;
|
||||
|
||||
destructor taoptbase.destroy;
|
||||
begin
|
||||
inherited destroy;
|
||||
end;
|
||||
|
||||
|
||||
Function TAOptBase.RegInInstruction(Reg: TRegister; p1: tai): Boolean;
|
||||
Var Count: AWord;
|
||||
TmpResult: Boolean;
|
||||
@ -124,7 +115,7 @@ Begin
|
||||
Count := 0;
|
||||
If (p1.typ = ait_instruction) Then
|
||||
Repeat
|
||||
TmpResult := RegInOp(Reg, PInstr(p1)^.oper[Count]);
|
||||
TmpResult := RegInOp(Reg, PInstr(p1)^.oper[Count]^);
|
||||
Inc(Count)
|
||||
Until (Count = MaxOps) or TmpResult;
|
||||
RegInInstruction := TmpResult
|
||||
@ -156,6 +147,11 @@ Begin
|
||||
Current := tai(Current.Next);
|
||||
While Assigned(Current) And
|
||||
((Current.typ In SkipInstr) or
|
||||
{$ifdef SPARC}
|
||||
((Current.typ=ait_instruction) and
|
||||
(taicpu(Current).opcode=A_NOP)
|
||||
) or
|
||||
{$endif SPARC}
|
||||
((Current.typ = ait_label) And
|
||||
Not(Tai_Label(Current).l.is_used))) Do
|
||||
Current := tai(Current.Next);
|
||||
@ -258,11 +254,15 @@ Begin
|
||||
Abstract
|
||||
End;
|
||||
|
||||
End.
|
||||
end.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.7 2004-06-20 08:55:28 florian
|
||||
Revision 1.8 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.7 2004/06/20 08:55:28 florian
|
||||
* logs truncated
|
||||
|
||||
}
|
||||
|
@ -24,12 +24,17 @@
|
||||
}
|
||||
Unit aoptda;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
Interface
|
||||
|
||||
uses aasm, cpubase, aoptcpub, aoptbase, aoptcpu;
|
||||
uses
|
||||
cpubase,cgbase,
|
||||
aasmbase,aasmtai,aasmcpu,
|
||||
aoptcpub, aoptbase;
|
||||
|
||||
Type
|
||||
TAOptDFA = Object(TAoptCpu)
|
||||
TAOptDFA = class
|
||||
{ uses the same constructor as TAoptCpu = constructor from TAoptObj }
|
||||
|
||||
{ gathers the information regarding the contents of every register }
|
||||
@ -44,47 +49,49 @@ Type
|
||||
InstrSinceLastMod: TInstrSinceLastMod;
|
||||
|
||||
{ convert a TInsChange value into the corresponding register }
|
||||
Function TCh2Reg(Ch: TInsChange): TRegister; Virtual;
|
||||
//!!!!!!!!!! Function TCh2Reg(Ch: TInsChange): TRegister; Virtual;
|
||||
{ returns whether the instruction P reads from register Reg }
|
||||
Function RegReadByInstr(Reg: TRegister; p: Pai): Boolean; Virtual;
|
||||
Function RegReadByInstr(Reg: TRegister; p: tai): Boolean; Virtual;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
uses globals, aoptobj;
|
||||
uses
|
||||
globals, aoptobj;
|
||||
|
||||
Procedure TAOptDFA.DoDFA;
|
||||
{ Analyzes the Data Flow of an assembler list. Analyses the reg contents }
|
||||
{ for the instructions between blockstart and blockend. Returns the last pai }
|
||||
{ which has been processed }
|
||||
Var
|
||||
CurProp: PPaiProp;
|
||||
CurProp: TPaiProp;
|
||||
UsedRegs: TUsedRegs;
|
||||
p, hp, NewBlockStart : Pai;
|
||||
p, hp, NewBlockStart : tai;
|
||||
TmpReg: TRegister;
|
||||
Begin
|
||||
{!!!!!!!!!!
|
||||
p := BlockStart;
|
||||
UsedRegs.init;
|
||||
UsedRegs.Create;
|
||||
UsedRegs.Update(p);
|
||||
NewBlockStart := SkipHead(p);
|
||||
{ done implicitely by the constructor
|
||||
FillChar(InstrSinceLastMod, SizeOf(InstrSinceLastMod), 0); }
|
||||
While (P <> BlockEnd) Do
|
||||
Begin
|
||||
CurProp := New(PPaiProp, init);
|
||||
CurProp:=TPaiProp.Create;
|
||||
If (p <> NewBlockStart) Then
|
||||
Begin
|
||||
GetLastInstruction(p, hp);
|
||||
CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
|
||||
CurProp.Regs := TPaiProp(hp.OptInfo).Regs;
|
||||
{ !!!!!!!!!!!! }
|
||||
{$ifdef x86}
|
||||
CurProp^.CondRegs.Flags :=
|
||||
PPaiProp(hp^.OptInfo)^.CondRegs.Flags;
|
||||
CurProp.CondRegs.Flags :=
|
||||
TPaiProp(hp.OptInfo).CondRegs.Flags;
|
||||
{$endif}
|
||||
End;
|
||||
CurProp^.UsedRegs.InitWithValue(UsedRegs.GetUsedRegs);
|
||||
UsedRegs.Update(Pai(p^.Next));
|
||||
PPaiProp(p^.OptInfo) := CurProp;
|
||||
CurProp.UsedRegs.InitWithValue(UsedRegs.GetUsedRegs);
|
||||
UsedRegs.Update(tai(p.Next));
|
||||
TPaiProp(p.OptInfo) := CurProp;
|
||||
For TmpReg := LoGPReg To HiGPReg Do
|
||||
Inc(InstrSinceLastMod[TmpReg]);
|
||||
Case p^.typ Of
|
||||
@ -153,6 +160,7 @@ Begin
|
||||
{ Inc(InstrCnt);}
|
||||
GetNextInstruction(p, p);
|
||||
End;
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TAoptDFA.CpuDFA(p: PInstr);
|
||||
@ -160,13 +168,15 @@ Begin
|
||||
Abstract;
|
||||
End;
|
||||
|
||||
{!!!!!!!
|
||||
Function TAOptDFA.TCh2Reg(Ch: TInsChange): TRegister;
|
||||
Begin
|
||||
TCh2Reg:=R_NO;
|
||||
Abstract;
|
||||
End;
|
||||
}
|
||||
|
||||
Function TAOptDFA.RegReadByInstr(Reg: TRegister; p: Pai): Boolean;
|
||||
Function TAOptDFA.RegReadByInstr(Reg: TRegister; p: tai): Boolean;
|
||||
Begin
|
||||
RegReadByInstr:=false;
|
||||
Abstract;
|
||||
@ -177,11 +187,14 @@ End.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.8 2004-06-20 08:55:28 florian
|
||||
Revision 1.9 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.8 2004/06/20 08:55:28 florian
|
||||
* logs truncated
|
||||
|
||||
Revision 1.7 2004/01/31 17:45:16 peter
|
||||
* Change several $ifdef i386 to x86
|
||||
* Change several OS_32 to OS_INT/OS_ADDR
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
$Id$
|
||||
Copyright (c) 1998-2002 by Jonas Maebe, member of the Free Pascal
|
||||
Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This unit contains the processor independent assembler optimizer
|
||||
@ -25,12 +25,19 @@
|
||||
}
|
||||
Unit AoptObj;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
{ general, processor independent objects for use by the assembler optimizer }
|
||||
|
||||
Interface
|
||||
|
||||
uses aasmbase,aasmcpu,aasmtai,
|
||||
cclasses, cpuinfo, cpubase, aoptbase, aoptcpub;
|
||||
uses
|
||||
globtype,
|
||||
aasmbase,aasmcpu,aasmtai,
|
||||
cclasses,
|
||||
cgbase,
|
||||
cpuinfo, cpubase,
|
||||
aoptbase, aoptcpub, aoptda;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ ********************************* Constants ***************************** }
|
||||
@ -51,17 +58,20 @@ Type
|
||||
{ ************************* Some general type definitions ***************** }
|
||||
{ ************************************************************************* }
|
||||
TRefCompare = Function(const r1, r2: TReference): Boolean;
|
||||
TRegArray = Array[LoReg..HiReg] of TRegister;
|
||||
TRegSet = Set of LoReg..HiReg;
|
||||
//!!! FIXME
|
||||
TRegArray = Array[byte] of tsuperregister;
|
||||
TRegSet = Set of byte;
|
||||
{ possible actions on an operand: read, write or modify (= read & write) }
|
||||
TOpAction = (OpAct_Read, OpAct_Write, OpAct_Modify, OpAct_Unknown);
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ * Object to hold information on which regiters are in use and which not * }
|
||||
{ ************************************************************************* }
|
||||
TUsedRegs = Object
|
||||
Constructor init;
|
||||
Constructor InitWithValue(Const _RegSet: TRegSet);
|
||||
TUsedRegs = class
|
||||
Constructor create;
|
||||
Constructor create_regset(Const _RegSet: TRegSet);
|
||||
|
||||
Destructor Destroy;override;
|
||||
{ update the info with the pairegalloc objects coming after }
|
||||
{ p }
|
||||
Procedure Update(p: Tai);
|
||||
@ -69,7 +79,6 @@ Type
|
||||
Function IsUsed(Reg: TRegister): Boolean;
|
||||
{ get all the currently used registers }
|
||||
Function GetUsedRegs: TRegSet;
|
||||
Destructor Done;
|
||||
|
||||
Private
|
||||
|
||||
@ -104,25 +113,22 @@ Type
|
||||
Typ: Byte;
|
||||
End;
|
||||
|
||||
TRegContent = Array[LoGPReg..HiGPReg] Of TContent;
|
||||
//!!! FIXME
|
||||
TRegContent = Array[byte] Of TContent;
|
||||
|
||||
{ ************************************************************************** }
|
||||
{ information object with the contents of every register. Every Tai object }
|
||||
{ gets one of these assigned: a pointer to it is stored in the OptInfo field }
|
||||
{ ************************************************************************** }
|
||||
|
||||
PPaiProp = ^TPaiProp;
|
||||
|
||||
TPaiProp = Object(TAoptBaseCpu)
|
||||
TPaiProp = class(TAoptBaseCpu)
|
||||
Regs: TRegContent;
|
||||
{ info about allocation of general purpose integer registers }
|
||||
UsedRegs: TUsedRegs;
|
||||
{ info about the conditional registers }
|
||||
CondRegs: TCondRegs;
|
||||
{ can this instruction be removed? }
|
||||
CanBeRemoved: Boolean;
|
||||
|
||||
Constructor init;
|
||||
Constructor create;
|
||||
|
||||
{ checks the whole sequence of which (so regs[which].StartMod and and }
|
||||
{ the next NrOfMods Tai objects) to see whether Reg is used somewhere, }
|
||||
@ -217,8 +223,8 @@ Type
|
||||
{ fragment }
|
||||
LowLabel, HighLabel: AWord;
|
||||
LabelDif: AWord;
|
||||
{ table that contains the addresses of the Pai_Label objects associated }
|
||||
{ with each label number }
|
||||
{ table that contains the addresses of the Pai_Label objects associated
|
||||
with each label number }
|
||||
LabelTable: PLabelTable;
|
||||
End;
|
||||
|
||||
@ -226,7 +232,7 @@ Type
|
||||
{ ********** General optimizer object, used to derive others from ********* }
|
||||
{ ************************************************************************* }
|
||||
|
||||
TAOptObj = Object(TAoptBaseCpu)
|
||||
TAOptObj = class(TAoptBaseCpu)
|
||||
{ the PAasmOutput list this optimizer instance works on }
|
||||
AsmL: TAasmOutput;
|
||||
|
||||
@ -238,11 +244,12 @@ Type
|
||||
{ Start and end of the block that is currently being optimized }
|
||||
BlockStart, BlockEnd: Tai;
|
||||
|
||||
DFA: TAOptDFA;
|
||||
{ _AsmL is the PAasmOutpout list that has to be optimized, }
|
||||
{ _BlockStart and _BlockEnd the start and the end of the block }
|
||||
{ that has to be optimized and _LabelInfo a pointer to a }
|
||||
{ TLabelInfo record }
|
||||
Constructor Init(_AsmL: TAasmOutput; _BlockStart, _BlockEnd: Tai;
|
||||
Constructor create(_AsmL: TAasmOutput; _BlockStart, _BlockEnd: Tai;
|
||||
_LabelInfo: PLabelInfo);
|
||||
|
||||
{ processor independent methods }
|
||||
@ -255,21 +262,41 @@ Type
|
||||
Procedure InsertLLItem(prev, foll, new_one: TLinkedListItem);
|
||||
|
||||
|
||||
{ If P is a Tai object releveant to the optimizer, P is returned }
|
||||
{ If it is not relevant tot he optimizer, the first object after P }
|
||||
{ that is relevant is returned }
|
||||
{ If P is a Tai object releveant to the optimizer, P is returned
|
||||
If it is not relevant tot he optimizer, the first object after P
|
||||
that is relevant is returned }
|
||||
Function SkipHead(P: Tai): Tai;
|
||||
|
||||
{ returns true if the operands o1 and o2 are completely equal }
|
||||
Function OpsEqual(const o1,o2:toper): Boolean;
|
||||
|
||||
{ Returns true if a ait_alloc object for Reg is found in the block }
|
||||
{ of Tai's starting with StartPai and ending with the next "real" }
|
||||
{ instruction }
|
||||
{ Returns true if a ait_alloc object for Reg is found in the block
|
||||
of Tai's starting with StartPai and ending with the next "real"
|
||||
instruction }
|
||||
Function FindRegAlloc(Reg: TRegister; StartPai: Tai): Boolean;
|
||||
|
||||
{ processor dependent methods }
|
||||
{ traces sucessive jumps to their final destination and sets it, e.g.
|
||||
je l1 je l3
|
||||
<code> <code>
|
||||
l1: becomes l1:
|
||||
je l2 je l3
|
||||
<code> <code>
|
||||
l2: l2:
|
||||
jmp l3 jmp l3
|
||||
|
||||
the level parameter denotes how deeep we have already followed the jump,
|
||||
to avoid endless loops with constructs such as "l5: ; jmp l5" }
|
||||
function GetFinalDestination(hp: taicpu; level: longint): boolean;
|
||||
|
||||
function getlabelwithsym(sym: tasmlabel): tai;
|
||||
|
||||
{ peephole optimizer }
|
||||
procedure PrePeepHoleOpts;virtual;
|
||||
procedure PeepHoleOptPass1;virtual;
|
||||
procedure PeepHoleOptPass2;virtual;
|
||||
procedure PostPeepHoleOpts;virtual;
|
||||
|
||||
{ processor dependent methods }
|
||||
End;
|
||||
|
||||
Function ArrayRefsEq(const r1, r2: TReference): Boolean;
|
||||
@ -278,18 +305,21 @@ Type
|
||||
|
||||
Implementation
|
||||
|
||||
uses globtype, globals, cgbase;
|
||||
uses
|
||||
globals,
|
||||
verbose,
|
||||
procinfo;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ ******************************** TUsedRegs ****************************** }
|
||||
{ ************************************************************************* }
|
||||
|
||||
Constructor TUsedRegs.init;
|
||||
Constructor TUsedRegs.create;
|
||||
Begin
|
||||
UsedRegs := [];
|
||||
End;
|
||||
|
||||
Constructor TUsedRegs.InitWithValue(Const _RegSet: TRegSet);
|
||||
Constructor TUsedRegs.create_regset(Const _RegSet: TRegSet);
|
||||
Begin
|
||||
UsedRegs := _RegSet;
|
||||
End;
|
||||
@ -306,11 +336,13 @@ Begin
|
||||
While Assigned(p) And
|
||||
(p.typ=ait_RegAlloc) Do
|
||||
Begin
|
||||
if tai_regalloc(p).allocation then
|
||||
{!!!!!!!! FIXME
|
||||
if tai_regalloc(p).ratype=ra_alloc then
|
||||
UsedRegs := UsedRegs + [tai_regalloc(p).Reg]
|
||||
else
|
||||
UsedRegs := UsedRegs - [tai_regalloc(p).Reg];
|
||||
p := Tai(p.next);
|
||||
}
|
||||
End;
|
||||
Until Not(Assigned(p)) Or
|
||||
(Not(p.typ in SkipInstr) And
|
||||
@ -320,7 +352,7 @@ End;
|
||||
|
||||
Function TUsedRegs.IsUsed(Reg: TRegister): Boolean;
|
||||
Begin
|
||||
IsUsed := Reg in UsedRegs
|
||||
//!!!!!!!!!!! IsUsed := Reg in UsedRegs
|
||||
End;
|
||||
|
||||
Function TUsedRegs.GetUsedRegs: TRegSet;
|
||||
@ -328,18 +360,21 @@ Begin
|
||||
GetUsedRegs := UsedRegs;
|
||||
End;
|
||||
|
||||
Destructor TUsedRegs.Done; {$ifdef inl} inline; {$endif inl}
|
||||
Destructor TUsedRegs.Destroy;
|
||||
Begin
|
||||
inherited destroy;
|
||||
end;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TPaiProp *********************************** }
|
||||
{ ************************************************************************* }
|
||||
|
||||
Constructor TPaiProp.Init;
|
||||
Constructor TPaiProp.Create;
|
||||
Begin
|
||||
{!!!!!!
|
||||
UsedRegs.Init;
|
||||
CondRegs.init;
|
||||
}
|
||||
{ DirFlag: TFlagContents; I386 specific}
|
||||
End;
|
||||
|
||||
@ -350,6 +385,7 @@ Var p: Tai;
|
||||
Counter: Byte;
|
||||
TmpResult: Boolean;
|
||||
Begin
|
||||
{!!!!!!!!!!1
|
||||
RegsChecked := [];
|
||||
content := regs[which];
|
||||
p := content.StartMod;
|
||||
@ -359,15 +395,15 @@ Begin
|
||||
(Counter <= Content.NrOfMods) Do
|
||||
Begin
|
||||
If IsLoadMemReg(p) Then
|
||||
With PInstr(p)^.oper[LoadSrc].ref^ Do
|
||||
With PInstr(p)^.oper[LoadSrc]^.ref^ Do
|
||||
If (Base = ProcInfo.FramePointer)
|
||||
{$ifdef RefsHaveIndexReg}
|
||||
And (Index = R_NO)
|
||||
{$endif RefsHaveIndexReg} Then
|
||||
Begin
|
||||
RegsChecked := RegsChecked +
|
||||
[RegMaxSize(PInstr(p)^.oper[LoadDst].reg)];
|
||||
If Reg = RegMaxSize(PInstr(p)^.oper[LoadDst].reg) Then
|
||||
[RegMaxSize(PInstr(p)^.oper[LoadDst]^.reg)];
|
||||
If Reg = RegMaxSize(PInstr(p)^.oper[LoadDst]^.reg) Then
|
||||
Break;
|
||||
End
|
||||
Else
|
||||
@ -387,6 +423,7 @@ Begin
|
||||
GetNextInstruction(p,p)
|
||||
End;
|
||||
RegInSequence := TmpResult
|
||||
}
|
||||
End;
|
||||
|
||||
|
||||
@ -397,6 +434,7 @@ Procedure TPaiProp.DestroyReg(Reg: TRegister; var InstrSinceLastMod:
|
||||
Var TmpWState, TmpRState: Byte;
|
||||
Counter: TRegister;
|
||||
Begin
|
||||
{!!!!!!!
|
||||
Reg := RegMaxSize(Reg);
|
||||
If (Reg in [LoGPReg..HiGPReg]) Then
|
||||
For Counter := LoGPReg to HiGPReg Do
|
||||
@ -413,16 +451,19 @@ Begin
|
||||
WState := TmpWState;
|
||||
RState := TmpRState
|
||||
End
|
||||
}
|
||||
End;
|
||||
|
||||
Function ArrayRefsEq(const r1, r2: TReference): Boolean;
|
||||
Begin
|
||||
{!!!!!!!!!!
|
||||
ArrayRefsEq := (R1.Offset+R1.OffsetFixup = R2.Offset+R2.OffsetFixup) And
|
||||
{$ifdef refsHaveSegmentReg}
|
||||
(R1.Segment = R2.Segment) And
|
||||
{$endif}
|
||||
(R1.Base = R2.Base) And
|
||||
(R1.Symbol=R2.Symbol);
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister;
|
||||
@ -433,6 +474,7 @@ Procedure TPaiProp.DestroyRefs(Const Ref: TReference; WhichReg: TRegister;
|
||||
Var RefsEq: TRefCompare;
|
||||
Counter: TRegister;
|
||||
Begin
|
||||
{!!!!!!!!!!!
|
||||
WhichReg := RegMaxSize(WhichReg);
|
||||
If (Ref.base = procinfo.FramePointer) or
|
||||
Assigned(Ref.Symbol) Then
|
||||
@ -503,11 +545,13 @@ Begin
|
||||
)
|
||||
)
|
||||
Then DestroyReg(Counter, InstrSinceLastMod)
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.DestroyAllRegs(var InstrSinceLastMod: TInstrSinceLastMod);
|
||||
Var Counter: TRegister;
|
||||
Begin {initializes/desrtoys all registers}
|
||||
{!!!!!!!!!
|
||||
For Counter := LoGPReg To HiGPReg Do
|
||||
Begin
|
||||
ReadReg(Counter);
|
||||
@ -515,11 +559,13 @@ Begin {initializes/desrtoys all registers}
|
||||
End;
|
||||
CondRegs.Init;
|
||||
{ FPURegs.Init; }
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.DestroyOp(const o:Toper; var InstrSinceLastMod:
|
||||
TInstrSinceLastMod);
|
||||
Begin
|
||||
{!!!!!!!
|
||||
Case o.typ Of
|
||||
top_reg: DestroyReg(o.reg, InstrSinceLastMod);
|
||||
top_ref:
|
||||
@ -529,23 +575,28 @@ Begin
|
||||
End;
|
||||
top_symbol:;
|
||||
End;
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.ReadReg(Reg: TRegister);
|
||||
Begin
|
||||
{!!!!!!!
|
||||
Reg := RegMaxSize(Reg);
|
||||
If Reg in General_Registers Then
|
||||
IncRState(RegMaxSize(Reg))
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.ReadRef(Ref: PReference);
|
||||
Begin
|
||||
{!!!!!!!
|
||||
If Ref^.Base <> R_NO Then
|
||||
ReadReg(Ref^.Base);
|
||||
{$ifdef refsHaveIndexReg}
|
||||
If Ref^.Index <> R_NO Then
|
||||
ReadReg(Ref^.Index);
|
||||
{$endif}
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.ReadOp(const o:toper);
|
||||
@ -553,13 +604,15 @@ Begin
|
||||
Case o.typ Of
|
||||
top_reg: ReadReg(o.reg);
|
||||
top_ref: ReadRef(o.ref);
|
||||
top_symbol : ;
|
||||
else
|
||||
internalerror(200410241);
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.ModifyReg(reg: TRegister; Var InstrSinceLastMod:
|
||||
TInstrSinceLastMod);
|
||||
Begin
|
||||
{!!!!!!!
|
||||
With Regs[reg] Do
|
||||
If (Typ = Con_Ref)
|
||||
Then
|
||||
@ -574,6 +627,7 @@ Begin
|
||||
End
|
||||
Else
|
||||
DestroyReg(Reg, InstrSinceLastMod);
|
||||
}
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.ModifyOp(const oper: TOper; var InstrSinceLastMod:
|
||||
@ -590,33 +644,33 @@ End;
|
||||
|
||||
Procedure TPaiProp.IncWState(Reg: TRegister);{$ifdef inl} inline;{$endif inl}
|
||||
Begin
|
||||
IncState(Regs[Reg].WState);
|
||||
//!!!! IncState(Regs[Reg].WState);
|
||||
End;
|
||||
|
||||
Procedure TPaiProp.IncRState(Reg: TRegister);{$ifdef inl} inline;{$endif inl}
|
||||
Begin
|
||||
IncState(Regs[Reg].RState);
|
||||
//!!!! IncState(Regs[Reg].RState);
|
||||
End;
|
||||
|
||||
Function TPaiProp.GetWState(Reg: TRegister): TStateInt; {$ifdef inl} inline;{$endif inl}
|
||||
Begin
|
||||
GetWState := Regs[Reg].WState
|
||||
//!!!! GetWState := Regs[Reg].WState
|
||||
End;
|
||||
|
||||
Function TPaiProp.GetRState(Reg: TRegister): TStateInt; {$ifdef inl} inline;{$endif inl}
|
||||
Begin
|
||||
GetRState := Regs[Reg].RState
|
||||
//!!!! GetRState := Regs[Reg].RState
|
||||
End;
|
||||
|
||||
Function TPaiProp.GetRegContentType(Reg: TRegister): Byte; {$ifdef inl} inline;{$endif inl}
|
||||
Begin
|
||||
GetRegContentType := Regs[Reg].typ
|
||||
//!!!! GetRegContentType := Regs[Reg].typ
|
||||
End;
|
||||
|
||||
Destructor TPaiProp.Done;
|
||||
Begin
|
||||
UsedRegs.Done;
|
||||
CondRegs.Done;
|
||||
//!!!! UsedRegs.Done;
|
||||
//!!!! CondRegs.Done;
|
||||
{ DirFlag: TFlagContents; I386 specific}
|
||||
End;
|
||||
{ ************************ private TPaiProp stuff ************************* }
|
||||
@ -637,8 +691,8 @@ Begin
|
||||
Begin
|
||||
Count := 0;
|
||||
Repeat
|
||||
If (TInstr(p).oper[Count].typ = Top_Ref) Then
|
||||
TmpResult := RefsEq(Ref, PInstr(p)^.oper[Count].ref^);
|
||||
If (TInstr(p).oper[Count]^.typ = Top_Ref) Then
|
||||
TmpResult := RefsEq(Ref, PInstr(p)^.oper[Count]^.ref^);
|
||||
Inc(Count);
|
||||
Until (Count = MaxOps) or TmpResult;
|
||||
End;
|
||||
@ -670,7 +724,7 @@ End;
|
||||
{ ***************************** TAoptObj ********************************** }
|
||||
{ ************************************************************************* }
|
||||
|
||||
Constructor TAoptObj.Init(_AsmL: TAasmOutput; _BlockStart, _BlockEnd: Tai;
|
||||
Constructor TAoptObj.create(_AsmL: TAasmOutput; _BlockStart, _BlockEnd: Tai;
|
||||
_LabelInfo: PLabelInfo);
|
||||
Begin
|
||||
AsmL := _AsmL;
|
||||
@ -708,6 +762,9 @@ Begin
|
||||
new_one.next := foll;
|
||||
prev.next := new_one;
|
||||
foll.previous := new_one;
|
||||
{ should we update line information? }
|
||||
if (not (tai(new_one).typ in SkipLineInfo)) and
|
||||
(not (tai(foll).typ in SkipLineInfo)) then
|
||||
Tailineinfo(new_one).fileinfo := Tailineinfo(foll).fileinfo
|
||||
End
|
||||
End
|
||||
@ -752,8 +809,6 @@ Begin
|
||||
OpsEqual := RefsEqual(o1.ref^, o2.ref^);
|
||||
Top_Const :
|
||||
OpsEqual:=o1.val=o2.val;
|
||||
Top_Symbol :
|
||||
OpsEqual:=(o1.sym=o2.sym) and (o1.symofs=o2.symofs);
|
||||
Top_None :
|
||||
OpsEqual := True
|
||||
else OpsEqual := False
|
||||
@ -770,7 +825,7 @@ Begin
|
||||
Not(Tai_Label(StartPai).l.Is_Used))) Do
|
||||
StartPai := Tai(StartPai.Next);
|
||||
If Assigned(StartPai) And
|
||||
(StartPai.typ = ait_regAlloc) and (tai_regalloc(StartPai).allocation) Then
|
||||
(StartPai.typ = ait_regAlloc) and (tai_regalloc(StartPai).ratype=ra_alloc) Then
|
||||
Begin
|
||||
if tai_regalloc(StartPai).Reg = Reg then
|
||||
begin
|
||||
@ -784,11 +839,257 @@ Begin
|
||||
Until false;
|
||||
End;
|
||||
|
||||
|
||||
function SkipLabels(hp: tai; var hp2: tai): boolean;
|
||||
{skips all labels and returns the next "real" instruction}
|
||||
begin
|
||||
while assigned(hp.next) and
|
||||
(tai(hp.next).typ in SkipInstr + [ait_label,ait_align]) Do
|
||||
hp := tai(hp.next);
|
||||
if assigned(hp.next) then
|
||||
begin
|
||||
SkipLabels := True;
|
||||
hp2 := tai(hp.next)
|
||||
end
|
||||
else
|
||||
begin
|
||||
hp2 := hp;
|
||||
SkipLabels := False
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
function FindAnyLabel(hp: tai; var l: tasmlabel): Boolean;
|
||||
begin
|
||||
FindAnyLabel := false;
|
||||
while assigned(hp.next) and
|
||||
(tai(hp.next).typ in (SkipInstr+[ait_align])) Do
|
||||
hp := tai(hp.next);
|
||||
if assigned(hp.next) and
|
||||
(tai(hp.next).typ = ait_label) then
|
||||
begin
|
||||
FindAnyLabel := true;
|
||||
l := tai_label(hp.next).l;
|
||||
end
|
||||
end;
|
||||
|
||||
|
||||
{$ifopt r+}
|
||||
{$define rangewason}
|
||||
{$r-}
|
||||
{$endif}
|
||||
function tAOptObj.getlabelwithsym(sym: tasmlabel): tai;
|
||||
begin
|
||||
if (sym.labelnr >= labelinfo^.lowlabel) and
|
||||
(sym.labelnr <= labelinfo^.highlabel) then { range check, a jump can go past an assembler block! }
|
||||
getlabelwithsym := labelinfo^.labeltable^[sym.labelnr-labelinfo^.lowlabel].paiobj
|
||||
else
|
||||
getlabelwithsym := nil;
|
||||
end;
|
||||
{$ifdef rangewason}
|
||||
{$r+}
|
||||
{$undef rangewason}
|
||||
{$endif}
|
||||
|
||||
function TAOptObj.GetFinalDestination(hp: taicpu; level: longint): boolean;
|
||||
{traces sucessive jumps to their final destination and sets it, e.g.
|
||||
je l1 je l3
|
||||
<code> <code>
|
||||
l1: becomes l1:
|
||||
je l2 je l3
|
||||
<code> <code>
|
||||
l2: l2:
|
||||
jmp l3 jmp l3
|
||||
|
||||
the level parameter denotes how deeep we have already followed the jump,
|
||||
to avoid endless loops with constructs such as "l5: ; jmp l5" }
|
||||
|
||||
var p1, p2: tai;
|
||||
l: tasmlabel;
|
||||
|
||||
begin
|
||||
if level > 20 then
|
||||
exit;
|
||||
GetfinalDestination := false;
|
||||
p1 := getlabelwithsym(tasmlabel(hp.oper[0]^.ref^.symbol));
|
||||
if assigned(p1) then
|
||||
begin
|
||||
SkipLabels(p1,p1);
|
||||
if (tai(p1).typ = ait_instruction) and
|
||||
(taicpu(p1).is_jmp) then
|
||||
if { the next instruction after the label where the jump hp arrives}
|
||||
{ is unconditional or of the same type as hp, so continue }
|
||||
(taicpu(p1).condition in [C_None,hp.condition]) or
|
||||
{ the next instruction after the label where the jump hp arrives}
|
||||
{ is the opposite of hp (so this one is never taken), but after }
|
||||
{ that one there is a branch that will be taken, so perform a }
|
||||
{ little hack: set p1 equal to this instruction (that's what the}
|
||||
{ last SkipLabels is for, only works with short bool evaluation)}
|
||||
((taicpu(p1).condition = inverse_cond[hp.condition]) and
|
||||
SkipLabels(p1,p2) and
|
||||
(p2.typ = ait_instruction) and
|
||||
(taicpu(p2).is_jmp) and
|
||||
(taicpu(p2).condition in [C_None,hp.condition]) and
|
||||
SkipLabels(p1,p1)) then
|
||||
begin
|
||||
{ quick check for loops of the form "l5: ; jmp l5 }
|
||||
if (tasmlabel(taicpu(p1).oper[0]^.ref^.symbol).labelnr =
|
||||
tasmlabel(hp.oper[0]^.ref^.symbol).labelnr) then
|
||||
exit;
|
||||
if not GetFinalDestination(taicpu(p1),succ(level)) then
|
||||
exit;
|
||||
tasmlabel(hp.oper[0]^.ref^.symbol).decrefs;
|
||||
hp.oper[0]^.ref^.symbol:=taicpu(p1).oper[0]^.ref^.symbol;
|
||||
tasmlabel(hp.oper[0]^.ref^.symbol).increfs;
|
||||
end
|
||||
else
|
||||
if (taicpu(p1).condition = inverse_cond[hp.condition]) then
|
||||
if not FindAnyLabel(p1,l) then
|
||||
begin
|
||||
{$ifdef finaldestdebug}
|
||||
insertllitem(asml,p1,p1.next,tai_comment.Create(
|
||||
strpnew('previous label inserted'))));
|
||||
{$endif finaldestdebug}
|
||||
objectlibrary.getlabel(l);
|
||||
insertllitem(p1,p1.next,tai_label.Create(l));
|
||||
tasmlabel(taicpu(hp).oper[0]^.ref^.symbol).decrefs;
|
||||
hp.oper[0]^.ref^.symbol := l;
|
||||
l.increfs;
|
||||
{ this won't work, since the new label isn't in the labeltable }
|
||||
{ so it will fail the rangecheck. Labeltable should become a }
|
||||
{ hashtable to support this: }
|
||||
{ GetFinalDestination(asml, hp); }
|
||||
end
|
||||
else
|
||||
begin
|
||||
{$ifdef finaldestdebug}
|
||||
insertllitem(asml,p1,p1.next,tai_comment.Create(
|
||||
strpnew('next label reused'))));
|
||||
{$endif finaldestdebug}
|
||||
l.increfs;
|
||||
hp.oper[0]^.ref^.symbol := l;
|
||||
if not GetFinalDestination(hp,succ(level)) then
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
GetFinalDestination := true;
|
||||
end;
|
||||
|
||||
|
||||
procedure TAOptObj.PrePeepHoleOpts;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TAOptObj.PeepHoleOptPass1;
|
||||
var
|
||||
p,hp1,hp2 : tai;
|
||||
begin
|
||||
p := BlockStart;
|
||||
//!!!! UsedRegs := [];
|
||||
while (p <> BlockEnd) Do
|
||||
begin
|
||||
//!!!! UpDateUsedRegs(UsedRegs, tai(p.next));
|
||||
case p.Typ Of
|
||||
ait_instruction:
|
||||
begin
|
||||
{ Handle Jmp Optimizations }
|
||||
if taicpu(p).is_jmp then
|
||||
begin
|
||||
{ the following if-block removes all code between a jmp and the next label,
|
||||
because it can never be executed
|
||||
}
|
||||
if (taicpu(p).opcode = aopt_uncondjmp) then
|
||||
begin
|
||||
while GetNextInstruction(p, hp1) and
|
||||
(hp1.typ <> ait_label) do
|
||||
if not(hp1.typ in ([ait_label,ait_align]+skipinstr)) then
|
||||
begin
|
||||
asml.remove(hp1);
|
||||
hp1.free;
|
||||
end
|
||||
else break;
|
||||
end;
|
||||
{ remove jumps to a label coming right after them }
|
||||
if GetNextInstruction(p, hp1) then
|
||||
begin
|
||||
if FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol), hp1) and
|
||||
{$warning FIXME removing the first instruction fails}
|
||||
(p<>blockstart) then
|
||||
begin
|
||||
hp2:=tai(hp1.next);
|
||||
asml.remove(p);
|
||||
p.free;
|
||||
p:=hp2;
|
||||
continue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if hp1.typ = ait_label then
|
||||
SkipLabels(hp1,hp1);
|
||||
if (tai(hp1).typ=ait_instruction) and
|
||||
(taicpu(hp1).opcode=aopt_uncondjmp) and
|
||||
GetNextInstruction(hp1, hp2) and
|
||||
FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol), hp2) then
|
||||
begin
|
||||
if taicpu(p).opcode=aopt_condjmp then
|
||||
begin
|
||||
taicpu(p).condition:=inverse_cond[taicpu(p).condition];
|
||||
tai_label(hp2).l.decrefs;
|
||||
taicpu(p).oper[0]^.ref^.symbol:=taicpu(hp1).oper[0]^.ref^.symbol;
|
||||
taicpu(p).oper[0]^.ref^.symbol.increfs;
|
||||
{$ifdef SPARC}
|
||||
hp2:=tai(hp1.next);
|
||||
asml.remove(hp2);
|
||||
hp2.free;
|
||||
{$endif SPARC}
|
||||
asml.remove(hp1);
|
||||
hp1.free;
|
||||
GetFinalDestination(taicpu(p),0);
|
||||
end
|
||||
else
|
||||
begin
|
||||
GetFinalDestination(taicpu(p),0);
|
||||
p:=tai(p.next);
|
||||
continue;
|
||||
end;
|
||||
end
|
||||
else
|
||||
GetFinalDestination(taicpu(p),0);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
{ All other optimizes }
|
||||
begin
|
||||
end; { if is_jmp }
|
||||
end;
|
||||
end;
|
||||
//!!!!!!!! updateUsedRegs(UsedRegs,p);
|
||||
p:=tai(p.next);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TAOptObj.PeepHoleOptPass2;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TAOptObj.PostPeepHoleOpts;
|
||||
begin
|
||||
end;
|
||||
|
||||
|
||||
End.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.11 2004-06-20 08:55:28 florian
|
||||
Revision 1.12 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.11 2004/06/20 08:55:28 florian
|
||||
* logs truncated
|
||||
|
||||
Revision 1.10 2004/01/31 17:45:17 peter
|
||||
@ -797,5 +1098,4 @@ End.
|
||||
|
||||
Revision 1.9 2004/01/30 13:42:03 florian
|
||||
* fixed more alignment issues
|
||||
|
||||
}
|
||||
|
@ -58,18 +58,15 @@
|
||||
{$define cpu64bit}
|
||||
{$define cpuextended}
|
||||
{$define cpufloat128}
|
||||
{$define noopt}
|
||||
{$define cputargethasfixedstack}
|
||||
{$endif x86_64}
|
||||
|
||||
{$ifdef alpha}
|
||||
{$define cpu64bit}
|
||||
{$define noopt}
|
||||
{$endif alpha}
|
||||
|
||||
{$ifdef sparc}
|
||||
{$define cpuflags}
|
||||
{$define noopt}
|
||||
{$define cputargethasfixedstack}
|
||||
{$define cpurequiresproperalignment}
|
||||
{$endif sparc}
|
||||
@ -84,19 +81,21 @@
|
||||
{$define cpuflags}
|
||||
{$define cpuneedsdiv32helper}
|
||||
{$define cputargethasfixedstack}
|
||||
{$define noopt}
|
||||
{$define cpurequiresproperalignment}
|
||||
{$endif arm}
|
||||
|
||||
{$ifdef m68k}
|
||||
{$define cpuflags}
|
||||
{$define cpufpemu}
|
||||
{$define noopt}
|
||||
{$endif m68k}
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.44 2004-10-14 18:29:22 peter
|
||||
Revision 1.45 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.44 2004/10/14 18:29:22 peter
|
||||
* disable USE_SYSUTILS when compiled with 1.9.4 or 1.0.x
|
||||
|
||||
Revision 1.43 2004/10/10 14:57:29 jonas
|
||||
|
@ -24,7 +24,6 @@ unit psub;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
@ -105,7 +104,7 @@ implementation
|
||||
{$ifdef i386}
|
||||
,aopt386
|
||||
{$else i386}
|
||||
,aoptcpu
|
||||
,aopt
|
||||
{$endif i386}
|
||||
{$endif}
|
||||
;
|
||||
@ -1404,7 +1403,11 @@ implementation
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.210 2004-10-24 20:01:08 peter
|
||||
Revision 1.211 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.210 2004/10/24 20:01:08 peter
|
||||
* remove saveregister calling convention
|
||||
|
||||
Revision 1.209 2004/10/15 09:14:17 mazen
|
||||
|
@ -1994,7 +1994,11 @@ unit rgobj;
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.144 2004-10-24 17:04:01 peter
|
||||
Revision 1.145 2004-10-30 15:21:37 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.144 2004/10/24 17:04:01 peter
|
||||
* during translation only process regalloc for the current regtype
|
||||
|
||||
Revision 1.143 2004/10/15 09:14:17 mazen
|
||||
|
@ -208,6 +208,7 @@ implementation
|
||||
constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol);
|
||||
begin
|
||||
inherited create(op);
|
||||
is_jmp:=op in [A_BA,A_Bxx];
|
||||
condition:=cond;
|
||||
ops:=1;
|
||||
loadsymbol(0,_op1,0);
|
||||
@ -217,6 +218,7 @@ implementation
|
||||
constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
|
||||
begin
|
||||
inherited create(op);
|
||||
is_jmp:=op in [A_BA,A_Bxx];
|
||||
ops:=1;
|
||||
loadsymbol(0,_op1,0);
|
||||
end;
|
||||
@ -311,7 +313,11 @@ begin
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.50 2004-06-20 08:55:32 florian
|
||||
Revision 1.51 2004-10-30 15:21:38 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.50 2004/06/20 08:55:32 florian
|
||||
* logs truncated
|
||||
|
||||
Revision 1.49 2004/06/20 08:47:33 florian
|
||||
|
51
compiler/sparc/aoptcpu.pas
Normal file
51
compiler/sparc/aoptcpu.pas
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
$Id$
|
||||
Copyright (c) 1998-2004 by Jonas Maebe
|
||||
|
||||
This unit calls the optimization procedures to optimize the assembler
|
||||
code for sparc
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
|
||||
unit aoptcpu;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
Interface
|
||||
|
||||
uses
|
||||
cpubase, aoptobj, aoptcpub, aopt;
|
||||
|
||||
Type
|
||||
TCpuAsmOptimizer = class(TAsmOptimizer)
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
begin
|
||||
casmoptimizer:=TCpuAsmOptimizer;
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.1 2004-10-30 15:21:38 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.10 2004/06/20 08:55:31 florian
|
||||
* logs truncated
|
||||
}
|
132
compiler/sparc/aoptcpub.pas
Normal file
132
compiler/sparc/aoptcpub.pas
Normal file
@ -0,0 +1,132 @@
|
||||
{
|
||||
$Id$
|
||||
Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This unit contains several types and constants necessary for the
|
||||
optimizer to work on the sparc architecture
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
Unit aoptcpub; { Assembler OPTimizer CPU specific Base }
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
{ enable the following define if memory references can have both a base and }
|
||||
{ index register in 1 operand }
|
||||
|
||||
{$define RefsHaveIndexReg}
|
||||
|
||||
{ enable the following define if memory references can have a scaled index }
|
||||
|
||||
{ define RefsHaveScale}
|
||||
|
||||
{ enable the following define if memory references can have a segment }
|
||||
{ override }
|
||||
|
||||
{ define RefsHaveSegment}
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
cpubase,aasmcpu,AOptBase;
|
||||
|
||||
Type
|
||||
|
||||
{ type of a normal instruction }
|
||||
TInstr = Taicpu;
|
||||
PInstr = ^TInstr;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TCondRegs ********************************** }
|
||||
{ ************************************************************************* }
|
||||
{ Info about the conditional registers }
|
||||
TCondRegs = Object
|
||||
Constructor Init;
|
||||
Destructor Done;
|
||||
End;
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TAoptBaseCpu ******************************* }
|
||||
{ ************************************************************************* }
|
||||
|
||||
TAoptBaseCpu = class(TAoptBase)
|
||||
End;
|
||||
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ ******************************* Constants ******************************* }
|
||||
{ ************************************************************************* }
|
||||
Const
|
||||
|
||||
{ the maximum number of things (registers, memory, ...) a single instruction }
|
||||
{ changes }
|
||||
|
||||
MaxCh = 3;
|
||||
|
||||
{ the maximum number of operands an instruction has }
|
||||
|
||||
MaxOps = 3;
|
||||
|
||||
{Oper index of operand that contains the source (reference) with a load }
|
||||
{instruction }
|
||||
|
||||
LoadSrc = 0;
|
||||
|
||||
{Oper index of operand that contains the destination (register) with a load }
|
||||
{instruction }
|
||||
|
||||
LoadDst = 1;
|
||||
|
||||
{Oper index of operand that contains the source (register) with a store }
|
||||
{instruction }
|
||||
|
||||
StoreSrc = 0;
|
||||
|
||||
{Oper index of operand that contains the destination (reference) with a load }
|
||||
{instruction }
|
||||
|
||||
StoreDst = 1;
|
||||
|
||||
aopt_uncondjmp = A_BA;
|
||||
aopt_condjmp = A_Bxx;
|
||||
|
||||
Implementation
|
||||
|
||||
{ ************************************************************************* }
|
||||
{ **************************** TCondRegs ********************************** }
|
||||
{ ************************************************************************* }
|
||||
Constructor TCondRegs.init;
|
||||
Begin
|
||||
End;
|
||||
|
||||
Destructor TCondRegs.Done; {$ifdef inl} inline; {$endif inl}
|
||||
Begin
|
||||
End;
|
||||
|
||||
End.
|
||||
|
||||
{
|
||||
$Log$
|
||||
Revision 1.1 2004-10-30 15:21:38 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.6 2004/06/20 08:55:31 florian
|
||||
* logs truncated
|
||||
|
||||
}
|
43
compiler/sparc/aoptcpud.pas
Normal file
43
compiler/sparc/aoptcpud.pas
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
$Id$
|
||||
Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
|
||||
Development Team
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
****************************************************************************
|
||||
}
|
||||
Unit aoptcpud;
|
||||
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
aoptda;
|
||||
|
||||
type
|
||||
TAOptDFACpu = class(TAOptDFA)
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.1 2004-10-30 15:21:38 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
}
|
@ -393,6 +393,7 @@ uses
|
||||
Helpers
|
||||
*****************************************************************************}
|
||||
|
||||
function RefsEqual(Const r1,r2: TReference) : Boolean;
|
||||
function is_calljmp(o:tasmop):boolean;
|
||||
|
||||
procedure inverse_flags(var f: TResFlags);
|
||||
@ -427,6 +428,17 @@ implementation
|
||||
Helpers
|
||||
*****************************************************************************}
|
||||
|
||||
function RefsEqual(Const r1,r2: TReference) : Boolean;
|
||||
begin
|
||||
RefsEqual := (r1.Offset=r2.Offset) and
|
||||
(r1.Base=r2.Base) and
|
||||
(r1.Index=r2.Index) and
|
||||
(r1.symbol=r2.symbol) and
|
||||
(r1.relsymbol=r2.relsymbol) and
|
||||
(r1.refaddr=r2.refaddr);
|
||||
end;
|
||||
|
||||
|
||||
function is_calljmp(o:tasmop):boolean;
|
||||
const
|
||||
CallJmpOp=[A_JMPL..A_CBccc];
|
||||
@ -509,7 +521,11 @@ implementation
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.73 2004-10-25 17:04:51 peter
|
||||
Revision 1.74 2004-10-30 15:21:38 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.73 2004/10/25 17:04:51 peter
|
||||
* add saved_standard_registers
|
||||
|
||||
Revision 1.72 2004/09/21 17:25:13 peter
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
unit cputarg;
|
||||
|
||||
{$INCLUDE fpcdefs.inc}
|
||||
{$i fpcdefs.inc}
|
||||
|
||||
interface
|
||||
|
||||
@ -32,6 +32,10 @@ implementation
|
||||
uses
|
||||
systems { prevent a syntax error when nothing is included }
|
||||
|
||||
{$ifndef NOOPT}
|
||||
,aoptcpu
|
||||
{$endif NOOPT}
|
||||
|
||||
{**************************************
|
||||
Targets
|
||||
**************************************}
|
||||
@ -48,12 +52,16 @@ implementation
|
||||
**************************************}
|
||||
|
||||
,CpuGas
|
||||
|
||||
;
|
||||
|
||||
end.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.5 2004-06-20 08:55:32 florian
|
||||
* logs truncated
|
||||
Revision 1.6 2004-10-30 15:21:38 florian
|
||||
* fixed generic optimizer
|
||||
* enabled generic optimizer for sparc
|
||||
|
||||
Revision 1.5 2004/06/20 08:55:32 florian
|
||||
* logs truncated
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user