mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-28 22:28:17 +02:00
487 lines
20 KiB
ObjectPascal
487 lines
20 KiB
ObjectPascal
{
|
|
$Id$
|
|
Copyright (c) 1999 by Jonas Maebe, member of the Free Pascal
|
|
Development Team
|
|
|
|
This unit contains the assembler optimizer data flow analyzer.
|
|
|
|
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 aoptda;
|
|
|
|
Interface
|
|
|
|
uses Aasm, TAoptObj, TAoptCpu;
|
|
|
|
Type TAsmDFA = Object(TAoptCpu)
|
|
{ uses the same constructor as TAoptCpu = constructor from TAoptObj }
|
|
|
|
Destructor Done;
|
|
|
|
private
|
|
|
|
{ How many instructions are between the current instruction and the }
|
|
{ last one that modified the register }
|
|
NrOfInstrSinceLastMod: TInstrSinceLastMod;
|
|
|
|
Procedure BuildLabelTableAndFixRegAlloc;
|
|
Function FindLoHiLabels(BlockStart: Pai): Pai;
|
|
|
|
End;
|
|
|
|
Implementation
|
|
|
|
uses aoptmsc
|
|
{$ifdef i386}
|
|
, ao386msc
|
|
{$endif i386}
|
|
;
|
|
|
|
Destructor TAsmDFA.Done;
|
|
Begin
|
|
End;
|
|
|
|
Procedure TAsmOptimizer.DoDFAPass2;
|
|
{ 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;
|
|
Cnt, InstrCnt : Longint;
|
|
InstrProp: TAsmInstrucProp;
|
|
UsedRegs: TRegSet;
|
|
p, hp, NewBlockStart : Pai;
|
|
TmpRef: TReference;
|
|
TmpReg: TRegister;
|
|
{$ifdef AnalyzeLoops}
|
|
TmpState: Byte;
|
|
{$endif AnalyzeLoops}
|
|
Begin
|
|
p := BlockStart;
|
|
UsedRegs.init;
|
|
UsedRegs.Update(p);
|
|
NewBlockStart := SkipHead(p);
|
|
InstrCnt := 1;
|
|
{ done implicitely by the constructor
|
|
FillChar(NrOfInstrSinceLastMod, SizeOf(NrOfInstrSinceLastMod), 0); }
|
|
While (P <> BlockEnd) Do
|
|
Begin
|
|
CurProp := New(PPaiProp, init);
|
|
If (p <> NewBlockStart)
|
|
Then
|
|
Begin
|
|
{$ifdef JumpAnal}
|
|
If (p^.Typ <> ait_label) Then
|
|
{$endif JumpAnal}
|
|
Begin
|
|
GetLastInstruction(p, hp);
|
|
CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
|
|
CurProp^.CondRegs.Flags :=
|
|
PPaiProp(hp^.OptInfo)^.CondRegs.Flags;
|
|
End
|
|
End;
|
|
CurProp^.UsedRegs.InitWithValue(UsedRegs.GetUsedRegs);
|
|
{ CurProp^.CanBeRemoved := False;}
|
|
UsedRegs.Update(Pai(p^.Next)));
|
|
PPaiProp(p^.OptInfo) := CurProp;
|
|
For TmpReg := R_EAX To R_EDI Do
|
|
Inc(NrOfInstrSinceLastMod[TmpReg]);
|
|
Case p^.typ Of
|
|
ait_label:
|
|
{$Ifndef JumpAnal}
|
|
If (Pai_label(p)^.l^.is_used) Then
|
|
CurProp^.DestroyAllRegs;
|
|
{$Else JumpAnal}
|
|
Begin
|
|
If (Pai_Label(p)^.is_used) Then
|
|
With LTable^[Pai_Label(p)^.l^.labelnr-LoLab] Do
|
|
{$IfDef AnalyzeLoops}
|
|
If (RefsFound = Pai_Label(p)^.l^.RefCount)
|
|
{$Else AnalyzeLoops}
|
|
If (JmpsProcessed = Pai_Label(p)^.l^.RefCount)
|
|
{$EndIf AnalyzeLoops}
|
|
Then
|
|
{all jumps to this label have been found}
|
|
{$IfDef AnalyzeLoops}
|
|
If (JmpsProcessed > 0)
|
|
Then
|
|
{$EndIf AnalyzeLoops}
|
|
{we've processed at least one jump to this label}
|
|
Begin
|
|
If (GetLastInstruction(p, hp) And
|
|
Not(((hp^.typ = ait_instruction)) And
|
|
(pai386_labeled(hp)^.is_jmp))
|
|
Then
|
|
{previous instruction not a JMP -> the contents of the registers after the
|
|
previous intruction has been executed have to be taken into account as well}
|
|
For TmpReg := R_EAX to R_EDI Do
|
|
Begin
|
|
If (CurProp^.Regs[TmpReg].WState <>
|
|
PPaiProp(hp^.OptInfo)^.Regs[TmpReg].WState)
|
|
Then DestroyReg(CurProp, TmpReg)
|
|
End
|
|
End
|
|
{$IfDef AnalyzeLoops}
|
|
Else
|
|
{a label from a backward jump (e.g. a loop), no jump to this label has
|
|
already been processed}
|
|
If GetLastInstruction(p, hp) And
|
|
Not(hp^.typ = ait_instruction) And
|
|
(pai386_labeled(hp)^.opcode = A_JMP))
|
|
Then
|
|
{previous instruction not a jmp, so keep all the registers' contents from the
|
|
previous instruction}
|
|
Begin
|
|
CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
|
|
CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
|
|
End
|
|
Else
|
|
{previous instruction a jmp and no jump to this label processed yet}
|
|
Begin
|
|
hp := p;
|
|
Cnt := InstrCnt;
|
|
{continue until we find a jump to the label or a label which has already
|
|
been processed}
|
|
While GetNextInstruction(hp, hp) And
|
|
Not((hp^.typ = ait_instruction) And
|
|
(pai386(hp)^.is_jmp) and
|
|
(pasmlabel(pai386(hp)^.oper[0].sym)^.labelnr = Pai_Label(p)^.l^.labelnr)) And
|
|
Not((hp^.typ = ait_label) And
|
|
(LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].RefsFound
|
|
= Pai_Label(hp)^.l^.RefCount) And
|
|
(LTable^[Pai_Label(hp)^.l^.labelnr-LoLab].JmpsProcessed > 0)) Do
|
|
Inc(Cnt);
|
|
If (hp^.typ = ait_label)
|
|
Then
|
|
{there's a processed label after the current one}
|
|
Begin
|
|
CurProp^.Regs := PaiPropBlock^[Cnt].Regs;
|
|
CurProp^.DirFlag := PaiPropBlock^[Cnt].DirFlag;
|
|
End
|
|
Else
|
|
{there's no label anymore after the current one, or they haven't been
|
|
processed yet}
|
|
Begin
|
|
GetLastInstruction(p, hp);
|
|
CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
|
|
CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
|
|
DestroyAllRegs(PPaiProp(hp^.OptInfo))
|
|
End
|
|
End
|
|
{$EndIf AnalyzeLoops}
|
|
Else
|
|
{not all references to this label have been found, so destroy all registers}
|
|
Begin
|
|
GetLastInstruction(p, hp);
|
|
CurProp^.Regs := PPaiProp(hp^.OptInfo)^.Regs;
|
|
CurProp^.DirFlag := PPaiProp(hp^.OptInfo)^.DirFlag;
|
|
DestroyAllRegs(CurProp)
|
|
End;
|
|
End;
|
|
{$EndIf JumpAnal}
|
|
|
|
{$ifdef GDB}
|
|
ait_stabs, ait_stabn, ait_stab_function_name:;
|
|
{$endif GDB}
|
|
|
|
ait_instruction:
|
|
Begin
|
|
if pai386(p)^.is_jmp then
|
|
begin
|
|
{$IfNDef JumpAnal}
|
|
;
|
|
{$Else JumpAnal}
|
|
With LTable^[pasmlabel(pai386(p)^.oper[0].sym)^.labelnr-LoLab] Do
|
|
If (RefsFound = pasmlabel(pai386(p)^.oper[0].sym)^.RefCount) Then
|
|
Begin
|
|
If (InstrCnt < InstrNr)
|
|
Then
|
|
{forward jump}
|
|
If (JmpsProcessed = 0) Then
|
|
{no jump to this label has been processed yet}
|
|
Begin
|
|
PaiPropBlock^[InstrNr].Regs := CurProp^.Regs;
|
|
PaiPropBlock^[InstrNr].DirFlag := CurProp^.DirFlag;
|
|
Inc(JmpsProcessed);
|
|
End
|
|
Else
|
|
Begin
|
|
For TmpReg := R_EAX to R_EDI Do
|
|
If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
|
|
CurProp^.Regs[TmpReg].WState) Then
|
|
DestroyReg(@PaiPropBlock^[InstrNr], TmpReg);
|
|
Inc(JmpsProcessed);
|
|
End
|
|
{$ifdef AnalyzeLoops}
|
|
Else
|
|
{ backward jump, a loop for example}
|
|
{ If (JmpsProcessed > 0) Or
|
|
Not(GetLastInstruction(PaiObj, hp) And
|
|
(hp^.typ = ait_labeled_instruction) And
|
|
(pai386_labeled(hp)^.opcode = A_JMP))
|
|
Then}
|
|
{instruction prior to label is not a jmp, or at least one jump to the label
|
|
has yet been processed}
|
|
Begin
|
|
Inc(JmpsProcessed);
|
|
For TmpReg := R_EAX to R_EDI Do
|
|
If (PaiPropBlock^[InstrNr].Regs[TmpReg].WState <>
|
|
CurProp^.Regs[TmpReg].WState)
|
|
Then
|
|
Begin
|
|
TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
|
|
Cnt := InstrNr;
|
|
While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
|
|
Begin
|
|
DestroyReg(@PaiPropBlock^[Cnt], TmpReg);
|
|
Inc(Cnt);
|
|
End;
|
|
While (Cnt <= InstrCnt) Do
|
|
Begin
|
|
Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
|
|
Inc(Cnt)
|
|
End
|
|
End;
|
|
End
|
|
{ Else }
|
|
{instruction prior to label is a jmp and no jumps to the label have yet been
|
|
processed}
|
|
{ Begin
|
|
Inc(JmpsProcessed);
|
|
For TmpReg := R_EAX to R_EDI Do
|
|
Begin
|
|
TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
|
|
Cnt := InstrNr;
|
|
While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
|
|
Begin
|
|
PaiPropBlock^[Cnt].Regs[TmpReg] := CurProp^.Regs[TmpReg];
|
|
Inc(Cnt);
|
|
End;
|
|
TmpState := PaiPropBlock^[InstrNr].Regs[TmpReg].WState;
|
|
While (TmpState = PaiPropBlock^[Cnt].Regs[TmpReg].WState) Do
|
|
Begin
|
|
DestroyReg(@PaiPropBlock^[Cnt], TmpReg);
|
|
Inc(Cnt);
|
|
End;
|
|
While (Cnt <= InstrCnt) Do
|
|
Begin
|
|
Inc(PaiPropBlock^[Cnt].Regs[TmpReg].WState);
|
|
Inc(Cnt)
|
|
End
|
|
End
|
|
End}
|
|
{$endif AnalyzeLoops}
|
|
End;
|
|
{$EndIf JumpAnal}
|
|
end
|
|
else
|
|
begin
|
|
InstrProp := AsmInstr[PInstr(p)^.opcode];
|
|
If IsStoreInstr(p) Then
|
|
Begin
|
|
CurProp^.ReadReg(PInstr(p)^.oper[StoreSrc].reg);
|
|
CurProp^.ReadRef(PInstr(p)^.oper[StoreDst].ref);
|
|
CurProp^.DestroyRefs(PInstr(p)^.oper[StoreDst].ref^,
|
|
PInstr(p)^.oper[StoreSrc].reg);
|
|
End
|
|
Else If IsLoadInstr(p) Then
|
|
Begin
|
|
CurProp^.ReadRef(PInstr(p)^.oper[LoadSrc].ref);
|
|
CurProp^.ReadReg(PInstr(p)^.oper[LoadDst].reg);
|
|
TmpReg := RegMaxSize(PInstr(p)^.oper[1].reg);
|
|
If RegInRef(TmpReg, Pai386(p)^.oper[0].ref^) And
|
|
(CurProp^.Regs[TmpReg].Typ = Con_Ref)
|
|
Then
|
|
Begin
|
|
With CurProp^.Regs[TmpReg] Do
|
|
Begin
|
|
IncState(WState);
|
|
{also store how many instructions are part of the sequence in the first
|
|
instructions PPaiProp, so it can be easily accessed from within
|
|
CheckSequence}
|
|
Inc(NrOfMods, NrOfInstrSinceLastMod[TmpReg]);
|
|
PPaiProp(Pai(StartMod)^.OptInfo)^.Regs[TmpReg].NrOfMods := NrOfMods;
|
|
NrOfInstrSinceLastMod[TmpReg] := 0;
|
|
End;
|
|
End
|
|
Else
|
|
Begin
|
|
DestroyReg(CurProp, TmpReg);
|
|
If Not(RegInRef(TmpReg, Pai386(p)^.oper[0].ref^)) Then
|
|
With CurProp^.Regs[TmpReg] Do
|
|
Begin
|
|
Typ := Con_Ref;
|
|
StartMod := p;
|
|
NrOfMods := 1;
|
|
End
|
|
End;
|
|
{$ifdef StateDebug}
|
|
hp := new(pai_asm_comment,init(strpnew(att_reg2str[TmpReg]+': '+tostr(CurProp^.Regs[TmpReg].WState))));
|
|
InsertLLItem(AsmL, p, p^.next, hp);
|
|
{$endif StateDebug}
|
|
|
|
End;
|
|
Top_Const:
|
|
Begin
|
|
Case Pai386(p)^.oper[1].typ Of
|
|
Top_Reg:
|
|
Begin
|
|
TmpReg := Reg32(Pai386(p)^.oper[1].reg);
|
|
With CurProp^.Regs[TmpReg] Do
|
|
Begin
|
|
DestroyReg(CurProp, TmpReg);
|
|
typ := Con_Const;
|
|
StartMod := p;
|
|
End
|
|
End;
|
|
Top_Ref:
|
|
Begin
|
|
ReadRef(CurProp, Pai386(p)^.oper[1].ref);
|
|
DestroyRefs(P, Pai386(p)^.oper[1].ref^, R_NO);
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
End;
|
|
A_IMUL:
|
|
Begin
|
|
ReadOp(CurProp, Pai386(p)^.oper[0]);
|
|
ReadOp(CurProp, Pai386(p)^.oper[1]);
|
|
If (Pai386(p)^.oper[2].typ = top_none) Then
|
|
If (Pai386(p)^.oper[1].typ = top_none) Then
|
|
Begin
|
|
DestroyReg(CurProp, R_EAX);
|
|
DestroyReg(CurProp, R_EDX)
|
|
End
|
|
Else
|
|
{$ifdef arithopt}
|
|
AddInstr2OpContents(Pai386(p), Pai386(p)^.oper[1])
|
|
{$else arithopt}
|
|
DestroyOp(p, Pai386(p)^.oper[1])
|
|
{$endif arithopt}
|
|
Else
|
|
{$ifdef arithopt}
|
|
AddInstr2OpContents(Pai386(p), Pai386(p)^.oper[2]);
|
|
{$else arithopt}
|
|
DestroyOp(p, Pai386(p)^.oper[2]);
|
|
{$endif arithopt}
|
|
End;
|
|
A_XOR:
|
|
Begin
|
|
ReadOp(CurProp, Pai386(p)^.oper[0]);
|
|
ReadOp(CurProp, Pai386(p)^.oper[1]);
|
|
If (Pai386(p)^.oper[0].typ = top_reg) And
|
|
(Pai386(p)^.oper[1].typ = top_reg) And
|
|
(Pai386(p)^.oper[0].reg = Pai386(p)^.oper[1].reg)
|
|
Then
|
|
Begin
|
|
DestroyReg(CurProp, Pai386(p)^.oper[0].reg);
|
|
CurProp^.Regs[Reg32(Pai386(p)^.oper[0].reg)].typ := Con_Const;
|
|
CurProp^.Regs[Reg32(Pai386(p)^.oper[0].reg)].StartMod := Pointer(0)
|
|
End
|
|
Else
|
|
DestroyOp(p, Pai386(p)^.oper[1]);
|
|
End
|
|
Else
|
|
Begin
|
|
Cnt := 1;
|
|
While (Cnt <= MaxCh) And
|
|
(InstrProp.Ch[Cnt] <> C_None) Do
|
|
Begin
|
|
Case InstrProp.Ch[Cnt] Of
|
|
C_REAX..C_REDI: ReadReg(CurProp,TCh2Reg(InstrProp.Ch[Cnt]));
|
|
C_WEAX..C_RWEDI:
|
|
Begin
|
|
If (InstrProp.Ch[Cnt] >= C_RWEAX) Then
|
|
ReadReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
|
|
DestroyReg(CurProp, TCh2Reg(InstrProp.Ch[Cnt]));
|
|
End;
|
|
{$ifdef arithopt}
|
|
C_MEAX..C_MEDI:
|
|
AddInstr2RegContents({$ifdef statedebug} asml, {$endif}
|
|
Pai386(p),
|
|
TCh2Reg(InstrProp.Ch[Cnt]));
|
|
{$endif arithopt}
|
|
C_CDirFlag: CurProp^.DirFlag := F_NotSet;
|
|
C_SDirFlag: CurProp^.DirFlag := F_Set;
|
|
C_Rop1: ReadOp(CurProp, Pai386(p)^.oper[0]);
|
|
C_Rop2: ReadOp(CurProp, Pai386(p)^.oper[1]);
|
|
C_ROp3: ReadOp(CurProp, Pai386(p)^.oper[2]);
|
|
C_Wop1..C_RWop1:
|
|
Begin
|
|
If (InstrProp.Ch[Cnt] in [C_RWop1]) Then
|
|
ReadOp(CurProp, Pai386(p)^.oper[0]);
|
|
DestroyOp(p, Pai386(p)^.oper[0]);
|
|
End;
|
|
{$ifdef arithopt}
|
|
C_Mop1:
|
|
AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
|
|
Pai386(p), Pai386(p)^.oper[0]);
|
|
{$endif arithopt}
|
|
C_Wop2..C_RWop2:
|
|
Begin
|
|
If (InstrProp.Ch[Cnt] = C_RWop2) Then
|
|
ReadOp(CurProp, Pai386(p)^.oper[1]);
|
|
DestroyOp(p, Pai386(p)^.oper[1]);
|
|
End;
|
|
{$ifdef arithopt}
|
|
C_Mop2:
|
|
AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
|
|
Pai386(p), Pai386(p)^.oper[1]);
|
|
{$endif arithopt}
|
|
C_WOp3..C_RWOp3:
|
|
Begin
|
|
If (InstrProp.Ch[Cnt] = C_RWOp3) Then
|
|
ReadOp(CurProp, Pai386(p)^.oper[2]);
|
|
DestroyOp(p, Pai386(p)^.oper[2]);
|
|
End;
|
|
{$ifdef arithopt}
|
|
C_Mop3:
|
|
AddInstr2OpContents({$ifdef statedebug} asml, {$endif}
|
|
Pai386(p), Pai386(p)^.oper[2]);
|
|
{$endif arithopt}
|
|
C_WMemEDI:
|
|
Begin
|
|
ReadReg(CurProp, R_EDI);
|
|
FillChar(TmpRef, SizeOf(TmpRef), 0);
|
|
TmpRef.Base := R_EDI;
|
|
DestroyRefs(p, TmpRef, R_NO)
|
|
End;
|
|
C_RFlags, C_WFlags, C_RWFlags, C_FPU:
|
|
Else
|
|
Begin
|
|
DestroyAllRegs(CurProp);
|
|
End;
|
|
End;
|
|
Inc(Cnt);
|
|
End
|
|
End;
|
|
end;
|
|
End;
|
|
End
|
|
Else
|
|
Begin
|
|
DestroyAllRegs(CurProp);
|
|
End;
|
|
End;
|
|
Inc(InstrCnt);
|
|
GetNextInstruction(p, p);
|
|
End;
|
|
End;
|
|
|
|
|
|
End. |