mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-10 11:18:45 +02:00
* better handling of exit(func_result) (no release of register that
holds the function result added) * several other small improvements for reg allocation fixes
This commit is contained in:
parent
d6bcb83f95
commit
b15a98cfa4
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
$Id$
|
$Id$
|
||||||
Copyright (c) 1998-2000 by Jonas Maebe
|
Copyright (c) 1998-2000 by Jonas Maebe, member of the Freepascal
|
||||||
|
development team
|
||||||
|
|
||||||
This unit contains the data flow analyzer and several helper procedures
|
This unit contains the data flow analyzer and several helper procedures
|
||||||
and functions.
|
and functions.
|
||||||
@ -73,6 +74,9 @@ Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
|||||||
Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
|
Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
|
||||||
Procedure SkipHead(var P: Pai);
|
Procedure SkipHead(var P: Pai);
|
||||||
|
|
||||||
|
Procedure RemoveLastDeallocForFuncRes(asmL: PAasmOutput; p: pai);
|
||||||
|
Function regLoadedWithNewValue(reg: tregister; canDependOnPrevValue: boolean;
|
||||||
|
hp: pai): boolean;
|
||||||
Procedure UpdateUsedRegs(Var UsedRegs: TRegSet; p: Pai);
|
Procedure UpdateUsedRegs(Var UsedRegs: TRegSet; p: Pai);
|
||||||
Function RegsEquivalent(OldReg, NewReg: TRegister; Var RegInfo: TRegInfo; OpAct: TopAction): Boolean;
|
Function RegsEquivalent(OldReg, NewReg: TRegister; Var RegInfo: TRegInfo; OpAct: TopAction): Boolean;
|
||||||
Function InstructionsEquivalent(p1, p2: Pai; Var RegInfo: TRegInfo): Boolean;
|
Function InstructionsEquivalent(p1, p2: Pai; Var RegInfo: TRegInfo): Boolean;
|
||||||
@ -218,7 +222,7 @@ Var
|
|||||||
Implementation
|
Implementation
|
||||||
|
|
||||||
Uses
|
Uses
|
||||||
globals, systems, strings, verbose, hcodegen;
|
globals, systems, strings, verbose, hcodegen, symconst;
|
||||||
|
|
||||||
Type
|
Type
|
||||||
TRefCompare = function(const r1, r2: TReference): Boolean;
|
TRefCompare = function(const r1, r2: TReference): Boolean;
|
||||||
@ -304,15 +308,14 @@ End;
|
|||||||
Function FindLoHiLabels(Var LowLabel, HighLabel, LabelDif: Longint; BlockStart: Pai): Pai;
|
Function FindLoHiLabels(Var LowLabel, HighLabel, LabelDif: Longint; BlockStart: Pai): Pai;
|
||||||
{Walks through the paasmlist to find the lowest and highest label number}
|
{Walks through the paasmlist to find the lowest and highest label number}
|
||||||
Var LabelFound: Boolean;
|
Var LabelFound: Boolean;
|
||||||
P: Pai;
|
P, lastP: Pai;
|
||||||
Begin
|
Begin
|
||||||
LabelFound := False;
|
LabelFound := False;
|
||||||
LowLabel := MaxLongint;
|
LowLabel := MaxLongint;
|
||||||
HighLabel := 0;
|
HighLabel := 0;
|
||||||
P := BlockStart;
|
P := BlockStart;
|
||||||
While Assigned(P) And
|
lastP := p;
|
||||||
((P^.typ <> Ait_Marker) Or
|
While Assigned(P) Do
|
||||||
(Pai_Marker(P)^.Kind <> AsmBlockStart)) Do
|
|
||||||
Begin
|
Begin
|
||||||
If (Pai(p)^.typ = ait_label) Then
|
If (Pai(p)^.typ = ait_label) Then
|
||||||
If (Pai_Label(p)^.l^.is_used)
|
If (Pai_Label(p)^.l^.is_used)
|
||||||
@ -324,19 +327,23 @@ Begin
|
|||||||
If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
|
If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
|
||||||
HighLabel := Pai_Label(p)^.l^.labelnr;
|
HighLabel := Pai_Label(p)^.l^.labelnr;
|
||||||
End;
|
End;
|
||||||
|
lastP := p;
|
||||||
GetNextInstruction(p, p);
|
GetNextInstruction(p, p);
|
||||||
End;
|
End;
|
||||||
FindLoHiLabels := p;
|
if (lastP^.typ = ait_marker) and
|
||||||
|
(pai_marker(lastP)^.kind = asmBlockStart) then
|
||||||
|
FindLoHiLabels := lastP
|
||||||
|
else FindLoHiLabels := nil;
|
||||||
If LabelFound
|
If LabelFound
|
||||||
Then LabelDif := HighLabel+1-LowLabel
|
Then LabelDif := HighLabel+1-LowLabel
|
||||||
Else LabelDif := 0;
|
Else LabelDif := 0;
|
||||||
End;
|
End;
|
||||||
|
|
||||||
Function FindRegAlloc(Reg: TRegister; StartPai: Pai): Boolean;
|
Function FindRegAlloc(Reg: TRegister; StartPai: Pai; alloc: boolean): Boolean;
|
||||||
{Returns true if a ait_alloc object for Reg is found in the block of Pai's
|
{ Returns true if a ait_alloc object for Reg is found in the block of Pai's }
|
||||||
starting with StartPai and ending with the next "real" instruction}
|
{ starting with StartPai and ending with the next "real" instruction }
|
||||||
Begin
|
Begin
|
||||||
FindRegAlloc:=False;
|
FindRegAlloc := false;
|
||||||
Repeat
|
Repeat
|
||||||
While Assigned(StartPai) And
|
While Assigned(StartPai) And
|
||||||
((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
|
((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
|
||||||
@ -344,29 +351,106 @@ Begin
|
|||||||
Not(Pai_Label(StartPai)^.l^.Is_Used))) Do
|
Not(Pai_Label(StartPai)^.l^.Is_Used))) Do
|
||||||
StartPai := Pai(StartPai^.Next);
|
StartPai := Pai(StartPai^.Next);
|
||||||
If Assigned(StartPai) And
|
If Assigned(StartPai) And
|
||||||
(StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation) Then
|
(StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation = alloc) Then
|
||||||
Begin
|
Begin
|
||||||
if PairegAlloc(StartPai)^.Reg = Reg then
|
if PairegAlloc(StartPai)^.Reg = Reg then
|
||||||
begin
|
begin
|
||||||
FindRegAlloc:=true;
|
FindRegAlloc:=true;
|
||||||
exit;
|
break;
|
||||||
end;
|
end;
|
||||||
StartPai := Pai(StartPai^.Next);
|
StartPai := Pai(StartPai^.Next);
|
||||||
End
|
End
|
||||||
else
|
else
|
||||||
exit;
|
break;
|
||||||
Until false;
|
Until false;
|
||||||
End;
|
End;
|
||||||
|
|
||||||
|
Procedure RemoveLastDeallocForFuncRes(asmL: PAasmOutput; p: pai);
|
||||||
|
|
||||||
|
Procedure DoRemoveLastDeallocForFuncRes(asmL: PAasmOutput; reg: TRegister);
|
||||||
|
var hp, hp2: pai;
|
||||||
|
begin
|
||||||
|
hp := nil;
|
||||||
|
hp2 := p;
|
||||||
|
repeat
|
||||||
|
hp2 := pai(hp2^.previous);
|
||||||
|
if assigned(hp2) and
|
||||||
|
(hp2^.typ = ait_regalloc) and
|
||||||
|
not(pairegalloc(hp2)^.allocation) and
|
||||||
|
(pairegalloc(hp2)^.reg = reg) then
|
||||||
|
begin
|
||||||
|
asml^.remove(hp2);
|
||||||
|
dispose(hp2,done);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
until not(assigned(hp2)) or
|
||||||
|
regInInstruction(reg,hp2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if assigned(procinfo^.returntype.def) then
|
||||||
|
case procinfo^.returntype.def^.deftype of
|
||||||
|
arraydef,recorddef,pointerdef,
|
||||||
|
stringdef,enumdef,procdef,objectdef,errordef,
|
||||||
|
filedef,setdef,procvardef,
|
||||||
|
classrefdef,forwarddef:
|
||||||
|
DoRemoveLastDeallocForFuncRes(asmL,R_EAX);
|
||||||
|
orddef:
|
||||||
|
if procinfo^.returntype.def^.size <> 0 then
|
||||||
|
begin
|
||||||
|
DoRemoveLastDeallocForFuncRes(asmL,R_EAX);
|
||||||
|
{ for int64/qword }
|
||||||
|
if procinfo^.returntype.def^.size = 8 then
|
||||||
|
DoRemoveLastDeallocForFuncRes(asmL,R_EDX);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure getFuncResRegs(var regs: TRegSet);
|
||||||
|
begin
|
||||||
|
regs := [];
|
||||||
|
if assigned(procinfo^.returntype.def) then
|
||||||
|
case procinfo^.returntype.def^.deftype of
|
||||||
|
arraydef,recorddef,pointerdef,
|
||||||
|
stringdef,enumdef,procdef,objectdef,errordef,
|
||||||
|
filedef,setdef,procvardef,
|
||||||
|
classrefdef,forwarddef:
|
||||||
|
regs := [R_EAX];
|
||||||
|
orddef:
|
||||||
|
if procinfo^.returntype.def^.size <> 0 then
|
||||||
|
begin
|
||||||
|
regs := [R_EAX];
|
||||||
|
{ for int64/qword }
|
||||||
|
if procinfo^.returntype.def^.size = 8 then
|
||||||
|
regs := regs + [R_EDX];
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
Procedure AddRegDeallocFor(asmL: paasmOutput; reg: TRegister; p: pai);
|
Procedure AddRegDeallocFor(asmL: paasmOutput; reg: TRegister; p: pai);
|
||||||
var hp1: pai;
|
var hp1: pai;
|
||||||
|
funcResRegs: TRegset;
|
||||||
|
funcResReg: boolean;
|
||||||
begin
|
begin
|
||||||
|
getFuncResRegs(funcResRegs);
|
||||||
|
funcResReg := reg in funcResRegs;
|
||||||
hp1 := p;
|
hp1 := p;
|
||||||
While GetLastInstruction(p, p) And
|
while not(funcResReg and
|
||||||
Not(RegInInstruction(reg, p)) Do
|
(p^.typ = ait_instruction) and
|
||||||
|
(paicpu(p)^.opcode = A_JMP) and
|
||||||
|
(pasmlabel(paicpu(p)^.oper[0].sym) = aktexit2label)) and
|
||||||
|
getLastInstruction(p, p) And
|
||||||
|
not(regInInstruction(reg, p)) Do
|
||||||
hp1 := p;
|
hp1 := p;
|
||||||
p := New(PaiRegAlloc, DeAlloc(reg));
|
{ don't insert a dealloc for registers which contain the function result }
|
||||||
InsertLLItem(AsmL, hp1^.previous, hp1, p);
|
{ if they are followed by a jump to the exit label (for exit(...)) }
|
||||||
|
if not((hp1^.typ = ait_instruction) and
|
||||||
|
(paicpu(hp1)^.opcode = A_JMP) and
|
||||||
|
(pasmlabel(paicpu(hp1)^.oper[0].sym) = aktexit2label)) then
|
||||||
|
begin
|
||||||
|
p := new(paiRegAlloc, deAlloc(reg));
|
||||||
|
insertLLItem(AsmL, hp1^.previous, hp1, p);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Procedure BuildLabelTableAndFixRegAlloc(asmL: PAasmOutput; Var LabelTable: PLabelTable; LowLabel: Longint;
|
Procedure BuildLabelTableAndFixRegAlloc(asmL: PAasmOutput; Var LabelTable: PLabelTable; LowLabel: Longint;
|
||||||
@ -375,7 +459,7 @@ Procedure BuildLabelTableAndFixRegAlloc(asmL: PAasmOutput; Var LabelTable: PLabe
|
|||||||
Also fixes some RegDeallocs like "# %eax released; push (%eax)"}
|
Also fixes some RegDeallocs like "# %eax released; push (%eax)"}
|
||||||
Var p, hp1, hp2, lastP: Pai;
|
Var p, hp1, hp2, lastP: Pai;
|
||||||
regCounter: TRegister;
|
regCounter: TRegister;
|
||||||
UsedRegs: TRegSet;
|
UsedRegs, funcResRegs: TRegSet;
|
||||||
Begin
|
Begin
|
||||||
UsedRegs := [];
|
UsedRegs := [];
|
||||||
If (LabelDif <> 0) Then
|
If (LabelDif <> 0) Then
|
||||||
@ -412,11 +496,11 @@ Begin
|
|||||||
addRegDeallocFor(asmL, paiRegAlloc(p)^.reg, p);
|
addRegDeallocFor(asmL, paiRegAlloc(p)^.reg, p);
|
||||||
End
|
End
|
||||||
else
|
else
|
||||||
Begin
|
begin
|
||||||
UsedRegs := UsedRegs - [paiRegAlloc(p)^.Reg];
|
UsedRegs := UsedRegs - [paiRegAlloc(p)^.Reg];
|
||||||
hp1 := p;
|
hp1 := p;
|
||||||
hp2 := nil;
|
hp2 := nil;
|
||||||
While Not(FindRegAlloc(paiRegAlloc(p)^.Reg, Pai(hp1^.Next))) And
|
While Not(FindRegAlloc(paiRegAlloc(p)^.Reg, Pai(hp1^.Next),true)) And
|
||||||
GetNextInstruction(hp1, hp1) And
|
GetNextInstruction(hp1, hp1) And
|
||||||
RegInInstruction(paiRegAlloc(p)^.Reg, hp1) Do
|
RegInInstruction(paiRegAlloc(p)^.Reg, hp1) Do
|
||||||
hp2 := hp1;
|
hp2 := hp1;
|
||||||
@ -426,16 +510,19 @@ Begin
|
|||||||
AsmL^.Remove(p);
|
AsmL^.Remove(p);
|
||||||
InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
|
InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
|
||||||
p := hp1;
|
p := hp1;
|
||||||
End;
|
|
||||||
End;
|
|
||||||
end;
|
end;
|
||||||
End;
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
repeat
|
repeat
|
||||||
lastP := p;
|
lastP := p;
|
||||||
P := Pai(P^.Next);
|
P := Pai(P^.Next);
|
||||||
until not(Assigned(p) And
|
until not(Assigned(p)) or
|
||||||
(p^.typ in (SkipInstr - [ait_regalloc])));
|
not(p^.typ in (SkipInstr - [ait_regalloc]));
|
||||||
End;
|
End;
|
||||||
|
{ don't add deallocation for function result variable }
|
||||||
|
getFuncResRegs(funcResRegs);
|
||||||
|
usedRegs := usedRegs - funcResRegs;
|
||||||
for regCounter := R_EAX to R_EDI do
|
for regCounter := R_EAX to R_EDI do
|
||||||
if regCounter in usedRegs then
|
if regCounter in usedRegs then
|
||||||
addRegDeallocFor(asmL,regCounter,lastP);
|
addRegDeallocFor(asmL,regCounter,lastP);
|
||||||
@ -783,8 +870,8 @@ End;
|
|||||||
|
|
||||||
{********************* GetNext and GetLastInstruction *********************}
|
{********************* GetNext and GetLastInstruction *********************}
|
||||||
Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
||||||
{skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the
|
{ skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
|
||||||
next pai object in Next. Returns false if there isn't any}
|
{ next pai object in Next. Returns false if there isn't any }
|
||||||
Begin
|
Begin
|
||||||
Repeat
|
Repeat
|
||||||
If (Current^.typ = ait_marker) And
|
If (Current^.typ = ait_marker) And
|
||||||
@ -817,7 +904,10 @@ Begin
|
|||||||
Not((Current^.typ In SkipInstr) or
|
Not((Current^.typ In SkipInstr) or
|
||||||
((Current^.typ = ait_label) And
|
((Current^.typ = ait_label) And
|
||||||
Not(Pai_Label(Current)^.l^.is_used)))
|
Not(Pai_Label(Current)^.l^.is_used)))
|
||||||
Then GetNextInstruction := True
|
Then
|
||||||
|
GetNextInstruction :=
|
||||||
|
not((current^.typ = ait_marker) and
|
||||||
|
(pai_marker(current)^.kind = asmBlockStart))
|
||||||
Else
|
Else
|
||||||
Begin
|
Begin
|
||||||
GetNextInstruction := False;
|
GetNextInstruction := False;
|
||||||
@ -882,18 +972,40 @@ Begin
|
|||||||
{a marker of the NoPropInfoStart can't be the first instruction of a
|
{a marker of the NoPropInfoStart can't be the first instruction of a
|
||||||
paasmoutput list}
|
paasmoutput list}
|
||||||
GetNextInstruction(Pai(P^.Previous),P);
|
GetNextInstruction(Pai(P^.Previous),P);
|
||||||
If (P^.Typ = Ait_Marker) And
|
{ If (P^.Typ = Ait_Marker) And
|
||||||
(Pai_Marker(P)^.Kind = AsmBlockStart) Then
|
(Pai_Marker(P)^.Kind = AsmBlockStart) Then
|
||||||
Begin
|
Begin
|
||||||
P := Pai(P^.Next);
|
P := Pai(P^.Next);
|
||||||
While (P^.typ <> Ait_Marker) Or
|
While (P^.typ <> Ait_Marker) Or
|
||||||
(Pai_Marker(P)^.Kind <> AsmBlockEnd) Do
|
(Pai_Marker(P)^.Kind <> AsmBlockEnd) Do
|
||||||
P := Pai(P^.Next)
|
P := Pai(P^.Next)
|
||||||
End;
|
End;}
|
||||||
Until P = OldP
|
Until P = OldP
|
||||||
End;
|
End;
|
||||||
{******************* The Data Flow Analyzer functions ********************}
|
{******************* The Data Flow Analyzer functions ********************}
|
||||||
|
|
||||||
|
function regLoadedWithNewValue(reg: tregister; canDependOnPrevValue: boolean;
|
||||||
|
hp: pai): boolean;
|
||||||
|
{ assumes reg is a 32bit register }
|
||||||
|
var p: paicpu;
|
||||||
|
begin
|
||||||
|
p := paicpu(hp);
|
||||||
|
regLoadedWithNewValue :=
|
||||||
|
assigned(hp) and
|
||||||
|
(hp^.typ = ait_instruction) and
|
||||||
|
(((p^.opcode = A_MOV) or
|
||||||
|
(p^.opcode = A_MOVZX) or
|
||||||
|
(p^.opcode = A_MOVSX) or
|
||||||
|
(p^.opcode = A_LEA)) and
|
||||||
|
(p^.oper[1].typ = top_reg) and
|
||||||
|
(Reg32(p^.oper[1].reg) = reg) and
|
||||||
|
(canDependOnPrevValue or
|
||||||
|
(p^.oper[0].typ <> top_ref) or
|
||||||
|
not regInRef(reg,p^.oper[0].ref^)) or
|
||||||
|
((p^.opcode = A_POP) and
|
||||||
|
(Reg32(p^.oper[0].reg) = reg)));
|
||||||
|
end;
|
||||||
|
|
||||||
Procedure UpdateUsedRegs(Var UsedRegs: TRegSet; p: Pai);
|
Procedure UpdateUsedRegs(Var UsedRegs: TRegSet; p: Pai);
|
||||||
{updates UsedRegs with the RegAlloc Information coming after P}
|
{updates UsedRegs with the RegAlloc Information coming after P}
|
||||||
Begin
|
Begin
|
||||||
@ -2019,7 +2131,12 @@ End.
|
|||||||
|
|
||||||
{
|
{
|
||||||
$Log$
|
$Log$
|
||||||
Revision 1.78 2000-01-13 13:07:06 jonas
|
Revision 1.79 2000-01-22 16:08:06 jonas
|
||||||
|
* better handling of exit(func_result) (no release of register that
|
||||||
|
holds the function result added)
|
||||||
|
* several other small improvements for reg allocation fixes
|
||||||
|
|
||||||
|
Revision 1.78 2000/01/13 13:07:06 jonas
|
||||||
* released -dalignreg
|
* released -dalignreg
|
||||||
* some small fixes to -dnewOptimizations helper procedures
|
* some small fixes to -dnewOptimizations helper procedures
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user