mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-01 01:02:36 +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$
|
||||
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
|
||||
and functions.
|
||||
@ -73,6 +74,9 @@ Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
||||
Function GetLastInstruction(Current: Pai; Var Last: Pai): Boolean;
|
||||
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);
|
||||
Function RegsEquivalent(OldReg, NewReg: TRegister; Var RegInfo: TRegInfo; OpAct: TopAction): Boolean;
|
||||
Function InstructionsEquivalent(p1, p2: Pai; Var RegInfo: TRegInfo): Boolean;
|
||||
@ -218,7 +222,7 @@ Var
|
||||
Implementation
|
||||
|
||||
Uses
|
||||
globals, systems, strings, verbose, hcodegen;
|
||||
globals, systems, strings, verbose, hcodegen, symconst;
|
||||
|
||||
Type
|
||||
TRefCompare = function(const r1, r2: TReference): Boolean;
|
||||
@ -304,15 +308,14 @@ End;
|
||||
Function FindLoHiLabels(Var LowLabel, HighLabel, LabelDif: Longint; BlockStart: Pai): Pai;
|
||||
{Walks through the paasmlist to find the lowest and highest label number}
|
||||
Var LabelFound: Boolean;
|
||||
P: Pai;
|
||||
P, lastP: Pai;
|
||||
Begin
|
||||
LabelFound := False;
|
||||
LowLabel := MaxLongint;
|
||||
HighLabel := 0;
|
||||
P := BlockStart;
|
||||
While Assigned(P) And
|
||||
((P^.typ <> Ait_Marker) Or
|
||||
(Pai_Marker(P)^.Kind <> AsmBlockStart)) Do
|
||||
lastP := p;
|
||||
While Assigned(P) Do
|
||||
Begin
|
||||
If (Pai(p)^.typ = ait_label) Then
|
||||
If (Pai_Label(p)^.l^.is_used)
|
||||
@ -324,19 +327,23 @@ Begin
|
||||
If (Pai_Label(p)^.l^.labelnr > HighLabel) Then
|
||||
HighLabel := Pai_Label(p)^.l^.labelnr;
|
||||
End;
|
||||
lastP := p;
|
||||
GetNextInstruction(p, p);
|
||||
End;
|
||||
FindLoHiLabels := p;
|
||||
if (lastP^.typ = ait_marker) and
|
||||
(pai_marker(lastP)^.kind = asmBlockStart) then
|
||||
FindLoHiLabels := lastP
|
||||
else FindLoHiLabels := nil;
|
||||
If LabelFound
|
||||
Then LabelDif := HighLabel+1-LowLabel
|
||||
Else LabelDif := 0;
|
||||
End;
|
||||
|
||||
Function FindRegAlloc(Reg: TRegister; StartPai: Pai): Boolean;
|
||||
{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}
|
||||
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 }
|
||||
{ starting with StartPai and ending with the next "real" instruction }
|
||||
Begin
|
||||
FindRegAlloc:=False;
|
||||
FindRegAlloc := false;
|
||||
Repeat
|
||||
While Assigned(StartPai) And
|
||||
((StartPai^.typ in (SkipInstr - [ait_regAlloc])) Or
|
||||
@ -344,29 +351,106 @@ Begin
|
||||
Not(Pai_Label(StartPai)^.l^.Is_Used))) Do
|
||||
StartPai := Pai(StartPai^.Next);
|
||||
If Assigned(StartPai) And
|
||||
(StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation) Then
|
||||
(StartPai^.typ = ait_regAlloc) and (PairegAlloc(StartPai)^.allocation = alloc) Then
|
||||
Begin
|
||||
if PairegAlloc(StartPai)^.Reg = Reg then
|
||||
begin
|
||||
FindRegAlloc:=true;
|
||||
exit;
|
||||
break;
|
||||
end;
|
||||
StartPai := Pai(StartPai^.Next);
|
||||
End
|
||||
else
|
||||
exit;
|
||||
break;
|
||||
Until false;
|
||||
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);
|
||||
var hp1: pai;
|
||||
funcResRegs: TRegset;
|
||||
funcResReg: boolean;
|
||||
begin
|
||||
getFuncResRegs(funcResRegs);
|
||||
funcResReg := reg in funcResRegs;
|
||||
hp1 := p;
|
||||
While GetLastInstruction(p, p) And
|
||||
Not(RegInInstruction(reg, p)) Do
|
||||
while not(funcResReg and
|
||||
(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;
|
||||
p := New(PaiRegAlloc, DeAlloc(reg));
|
||||
InsertLLItem(AsmL, hp1^.previous, hp1, p);
|
||||
{ don't insert a dealloc for registers which contain the function result }
|
||||
{ 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;
|
||||
|
||||
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)"}
|
||||
Var p, hp1, hp2, lastP: Pai;
|
||||
regCounter: TRegister;
|
||||
UsedRegs: TRegSet;
|
||||
UsedRegs, funcResRegs: TRegSet;
|
||||
Begin
|
||||
UsedRegs := [];
|
||||
If (LabelDif <> 0) Then
|
||||
@ -403,39 +487,42 @@ Begin
|
||||
ait_regAlloc:
|
||||
{ ESI and EDI are (de)allocated manually, don't mess with them }
|
||||
if not(paiRegAlloc(p)^.Reg in [R_EDI,R_ESI]) then
|
||||
begin
|
||||
if PairegAlloc(p)^.Allocation then
|
||||
Begin
|
||||
If Not(paiRegAlloc(p)^.Reg in UsedRegs) Then
|
||||
UsedRegs := UsedRegs + [paiRegAlloc(p)^.Reg]
|
||||
Else
|
||||
addRegDeallocFor(asmL, paiRegAlloc(p)^.reg, p);
|
||||
End
|
||||
else
|
||||
Begin
|
||||
UsedRegs := UsedRegs - [paiRegAlloc(p)^.Reg];
|
||||
hp1 := p;
|
||||
hp2 := nil;
|
||||
While Not(FindRegAlloc(paiRegAlloc(p)^.Reg, Pai(hp1^.Next))) And
|
||||
GetNextInstruction(hp1, hp1) And
|
||||
RegInInstruction(paiRegAlloc(p)^.Reg, hp1) Do
|
||||
hp2 := hp1;
|
||||
If hp2 <> nil Then
|
||||
Begin
|
||||
hp1 := Pai(p^.previous);
|
||||
AsmL^.Remove(p);
|
||||
InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
|
||||
p := hp1;
|
||||
End;
|
||||
End;
|
||||
end;
|
||||
End;
|
||||
begin
|
||||
if PairegAlloc(p)^.Allocation then
|
||||
Begin
|
||||
If Not(paiRegAlloc(p)^.Reg in UsedRegs) Then
|
||||
UsedRegs := UsedRegs + [paiRegAlloc(p)^.Reg]
|
||||
Else
|
||||
addRegDeallocFor(asmL, paiRegAlloc(p)^.reg, p);
|
||||
End
|
||||
else
|
||||
begin
|
||||
UsedRegs := UsedRegs - [paiRegAlloc(p)^.Reg];
|
||||
hp1 := p;
|
||||
hp2 := nil;
|
||||
While Not(FindRegAlloc(paiRegAlloc(p)^.Reg, Pai(hp1^.Next),true)) And
|
||||
GetNextInstruction(hp1, hp1) And
|
||||
RegInInstruction(paiRegAlloc(p)^.Reg, hp1) Do
|
||||
hp2 := hp1;
|
||||
If hp2 <> nil Then
|
||||
Begin
|
||||
hp1 := Pai(p^.previous);
|
||||
AsmL^.Remove(p);
|
||||
InsertLLItem(AsmL, hp2, Pai(hp2^.Next), p);
|
||||
p := hp1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
repeat
|
||||
lastP := p;
|
||||
P := Pai(P^.Next);
|
||||
until not(Assigned(p) And
|
||||
(p^.typ in (SkipInstr - [ait_regalloc])));
|
||||
until not(Assigned(p)) or
|
||||
not(p^.typ in (SkipInstr - [ait_regalloc]));
|
||||
End;
|
||||
{ don't add deallocation for function result variable }
|
||||
getFuncResRegs(funcResRegs);
|
||||
usedRegs := usedRegs - funcResRegs;
|
||||
for regCounter := R_EAX to R_EDI do
|
||||
if regCounter in usedRegs then
|
||||
addRegDeallocFor(asmL,regCounter,lastP);
|
||||
@ -783,8 +870,8 @@ End;
|
||||
|
||||
{********************* GetNext and GetLastInstruction *********************}
|
||||
Function GetNextInstruction(Current: Pai; Var Next: Pai): Boolean;
|
||||
{skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the
|
||||
next pai object in Next. Returns false if there isn't any}
|
||||
{ skips ait_regalloc, ait_regdealloc and ait_stab* objects and puts the }
|
||||
{ next pai object in Next. Returns false if there isn't any }
|
||||
Begin
|
||||
Repeat
|
||||
If (Current^.typ = ait_marker) And
|
||||
@ -817,7 +904,10 @@ Begin
|
||||
Not((Current^.typ In SkipInstr) or
|
||||
((Current^.typ = ait_label) And
|
||||
Not(Pai_Label(Current)^.l^.is_used)))
|
||||
Then GetNextInstruction := True
|
||||
Then
|
||||
GetNextInstruction :=
|
||||
not((current^.typ = ait_marker) and
|
||||
(pai_marker(current)^.kind = asmBlockStart))
|
||||
Else
|
||||
Begin
|
||||
GetNextInstruction := False;
|
||||
@ -882,18 +972,40 @@ Begin
|
||||
{a marker of the NoPropInfoStart can't be the first instruction of a
|
||||
paasmoutput list}
|
||||
GetNextInstruction(Pai(P^.Previous),P);
|
||||
If (P^.Typ = Ait_Marker) And
|
||||
{ If (P^.Typ = Ait_Marker) And
|
||||
(Pai_Marker(P)^.Kind = AsmBlockStart) Then
|
||||
Begin
|
||||
P := Pai(P^.Next);
|
||||
While (P^.typ <> Ait_Marker) Or
|
||||
(Pai_Marker(P)^.Kind <> AsmBlockEnd) Do
|
||||
P := Pai(P^.Next)
|
||||
End;
|
||||
End;}
|
||||
Until P = OldP
|
||||
End;
|
||||
{******************* 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);
|
||||
{updates UsedRegs with the RegAlloc Information coming after P}
|
||||
Begin
|
||||
@ -2019,7 +2131,12 @@ End.
|
||||
|
||||
{
|
||||
$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
|
||||
* some small fixes to -dnewOptimizations helper procedures
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user