mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-13 07:59:25 +02:00
266 lines
8.9 KiB
ObjectPascal
266 lines
8.9 KiB
ObjectPascal
{
|
||
Copyright (c) 1998-2004 by Jonas Maebe, member of the Free Pascal
|
||
Development Team
|
||
|
||
This unit contains the interface routines between the code generator
|
||
and the optimizer.
|
||
|
||
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 aopt;
|
||
|
||
{$i fpcdefs.inc}
|
||
|
||
Interface
|
||
|
||
Uses
|
||
aasmbase,aasmtai,aasmcpu,
|
||
aoptobj;
|
||
|
||
Type
|
||
TAsmOptimizer = class(TAoptObj)
|
||
|
||
{ _AsmL is the PAasmOutpout list that has to be optimized }
|
||
Constructor create(_AsmL: taasmoutput); virtual;
|
||
|
||
{ call the necessary optimizer procedures }
|
||
Procedure Optimize;
|
||
Destructor destroy;override;
|
||
|
||
private
|
||
procedure FindLoHiLabels;
|
||
Procedure BuildLabelTableAndFixRegAlloc;
|
||
procedure clear;
|
||
procedure pass_1;
|
||
End;
|
||
|
||
var
|
||
casmoptimizer : class of tasmoptimizer;
|
||
|
||
procedure Optimize(AsmL:taasmoutput);
|
||
|
||
Implementation
|
||
|
||
uses
|
||
globtype, globals,
|
||
aoptda,aoptcpu,aoptcpud;
|
||
|
||
Constructor TAsmOptimizer.create(_AsmL: taasmoutput);
|
||
Begin
|
||
inherited create(_asml,nil,nil,nil);
|
||
{setup labeltable, always necessary}
|
||
New(LabelInfo);
|
||
End;
|
||
|
||
procedure TAsmOptimizer.FindLoHiLabels;
|
||
{ 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, prev: tai;
|
||
Begin
|
||
LabelInfo^.LowLabel := High(AWord);
|
||
LabelInfo^.HighLabel := 0;
|
||
LabelInfo^.LabelDif := 0;
|
||
LabelInfo^.LabelTable:=nil;
|
||
LabelFound := False;
|
||
P := BlockStart;
|
||
prev := p;
|
||
With LabelInfo^ Do
|
||
Begin
|
||
While Assigned(P) And
|
||
((P.typ <> Ait_Marker) Or
|
||
(tai_Marker(P).Kind <> AsmBlockStart)) Do
|
||
Begin
|
||
If (p.typ = ait_label) Then
|
||
If (tai_Label(p).l.is_used) Then
|
||
Begin
|
||
LabelFound := True;
|
||
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;
|
||
prev := p;
|
||
GetNextInstruction(p, p)
|
||
End;
|
||
if (prev.typ = ait_marker) and
|
||
(tai_marker(prev).kind = asmblockstart) then
|
||
blockend := prev
|
||
else blockend := nil;
|
||
If LabelFound
|
||
Then LabelDif := HighLabel-LowLabel+1
|
||
Else LabelDif := 0
|
||
End
|
||
End;
|
||
|
||
Procedure TAsmOptimizer.BuildLabelTableAndFixRegAlloc;
|
||
{ 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: tai;
|
||
UsedRegs: TRegSet;
|
||
Begin
|
||
UsedRegs := [];
|
||
With LabelInfo^ Do
|
||
If (LabelDif <> 0) Then
|
||
Begin
|
||
GetMem(LabelTable, LabelDif*SizeOf(TLabelTableItem));
|
||
FillChar(LabelTable^, LabelDif*SizeOf(TLabelTableItem), 0);
|
||
p := BlockStart;
|
||
While (P <> BlockEnd) Do
|
||
Begin
|
||
Case p.typ Of
|
||
ait_Label:
|
||
If tai_label(p).l.is_used Then
|
||
LabelTable^[tai_label(p).l.labelnr-LowLabel].PaiObj := p;
|
||
ait_regAlloc:
|
||
begin
|
||
{!!!!!!!!!
|
||
if tai_regalloc(p).ratype=ra_alloc then
|
||
Begin
|
||
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(tai_regalloc(p).Reg, hp1)) Do
|
||
hp2:=hp1;
|
||
If hp2<>nil Then
|
||
Begin
|
||
hp1:=tai_regalloc.DeAlloc(tai_regalloc(p).Reg,hp2);
|
||
InsertLLItem(tai(hp2.previous), hp2, hp1);
|
||
End;
|
||
End;
|
||
End
|
||
else
|
||
Begin
|
||
UsedRegs := UsedRegs - [tai_regalloc(p).Reg];
|
||
hp1 := p;
|
||
hp2 := nil;
|
||
While Not(FindRegAlloc(tai_regalloc(p).Reg, tai(hp1.Next))) And
|
||
GetNextInstruction(hp1, hp1) And
|
||
RegInInstruction(tai_regalloc(p).Reg, hp1) Do
|
||
hp2 := hp1;
|
||
If hp2 <> nil Then
|
||
Begin
|
||
hp1 := tai(p.previous);
|
||
AsmL.Remove(p);
|
||
InsertLLItem(hp2, tai(hp2.Next), p);
|
||
p := hp1;
|
||
End
|
||
End
|
||
};
|
||
End
|
||
End;
|
||
P := tai(p.Next);
|
||
While Assigned(p) and
|
||
(p <> blockend) and
|
||
(p.typ in (SkipInstr - [ait_regalloc])) Do
|
||
P := tai(P.Next)
|
||
End;
|
||
End
|
||
End;
|
||
|
||
procedure tasmoptimizer.clear;
|
||
begin
|
||
if LabelInfo^.labeldif <> 0 then
|
||
begin
|
||
freemem(LabelInfo^.labeltable);
|
||
LabelInfo^.labeltable := nil;
|
||
end;
|
||
end;
|
||
|
||
procedure tasmoptimizer.pass_1;
|
||
begin
|
||
findlohilabels;
|
||
BuildLabelTableAndFixRegAlloc;
|
||
end;
|
||
|
||
|
||
Procedure TAsmOptimizer.Optimize;
|
||
Var
|
||
HP: tai;
|
||
pass: longint;
|
||
Begin
|
||
pass:=0;
|
||
BlockStart := tai(AsmL.First);
|
||
pass_1;
|
||
While Assigned(BlockStart) Do
|
||
Begin
|
||
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
|
||
// DFA:=TAOptDFACpu.Create(AsmL,BlockStart,BlockEnd,LabelInfo);
|
||
{ data flow analyzer }
|
||
// DFA.DoDFA;
|
||
{ common subexpression elimination }
|
||
{ CSE;}
|
||
End;
|
||
{ more peephole optimizations }
|
||
{ PeepHoleOptPass2;}
|
||
{ free memory<72>}
|
||
clear;
|
||
{ continue where we left off, BlockEnd is either the start of an }
|
||
{ assembler block or nil}
|
||
BlockStart := BlockEnd;
|
||
While Assigned(BlockStart) And
|
||
(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
|
||
(tai_Marker(Blockstart).Kind <> AsmBlockEnd)) Do;
|
||
{ blockstart now contains a tai_marker(asmblockend) }
|
||
If GetNextInstruction(BlockStart, HP) And
|
||
((HP.typ <> ait_Marker) Or
|
||
(Tai_Marker(HP).Kind <> AsmBlockStart)) Then
|
||
{ There is no assembler block anymore after the current one, so }
|
||
{ optimize the next block of "normal" instructions }
|
||
pass_1
|
||
{ Otherwise, skip the next assembler block }
|
||
else
|
||
blockStart := hp;
|
||
End
|
||
End;
|
||
End;
|
||
|
||
Destructor TAsmOptimizer.Destroy;
|
||
Begin
|
||
Dispose(LabelInfo)
|
||
End;
|
||
|
||
|
||
procedure Optimize(AsmL:taasmoutput);
|
||
var
|
||
p : TAsmOptimizer;
|
||
begin
|
||
p:=casmoptimizer.Create(AsmL);
|
||
p.Optimize;
|
||
p.free
|
||
end;
|
||
|
||
|
||
end.
|