* x86: CheckJumpMovTransferOpt now also copies over register deallocations to allow better optimisations

This commit is contained in:
J. Gareth "Curious Kit" Moreton 2022-10-22 22:24:39 +01:00 committed by FPK
parent a49c0f6e0c
commit fb66369a3b
3 changed files with 122 additions and 99 deletions

View File

@ -108,6 +108,8 @@ interface
ait_eabi_attribute
);
taitypes = set of taitype;
taiconst_type = (
aitconst_128bit,
aitconst_64bit,

View File

@ -60,12 +60,15 @@ unit aoptbase;
{ gets the next tai object after current that contains info relevant }
{ to the optimizer in p1. If there is none, it returns false and }
{ sets p1 to nil }
class function GetNextInstruction(Current: tai; out Next: tai): Boolean; static;
{ sets p1 to nil. If AlsoStopOn is set, it will also stop on these }
{ object types that are normally skipped over. }
class function GetNextInstruction(Current: tai; out Next: tai; AlsoStopOn: taitypes = []): Boolean; static;
{ gets the previous tai object after current that contains info }
{ relevant to the optimizer in last. If there is none, it returns }
{ false and sets last to nil }
class function GetLastInstruction(Current: tai; out Last: tai): Boolean; static;
{ false and sets last to nil. If AlsoStopOn is set, it will also }
{ stop on these object types that are normally skipped over. }
class function GetLastInstruction(Current: tai; out Last: tai; AlsoStopOn: taitypes = []): Boolean; static;
class function SkipEntryExitMarker(current: tai; out next: tai): boolean; static;
@ -185,12 +188,12 @@ unit aoptbase;
end;
class function TAOptBase.GetNextInstruction(Current: tai; out Next: tai): Boolean;
class function TAOptBase.GetNextInstruction(Current: tai; out Next: tai; AlsoStopOn: taitypes): Boolean;
Begin
Repeat
Current := tai(Current.Next);
While Assigned(Current) And
((Current.typ In SkipInstr) or
((Current.typ In SkipInstr - AlsoStopOn) or
{$ifdef cpudelayslot}
((Current.typ=ait_instruction) and
(taicpu(Current).opcode=A_NOP)
@ -223,7 +226,7 @@ unit aoptbase;
(Tai_Marker(Current).Kind <> mark_NoPropInfoEnd);
Next := Current;
If Assigned(Current) And
Not((Current.typ In SkipInstr) or
Not((Current.typ In SkipInstr - AlsoStopOn) or
((Current.typ = ait_label) And
labelCanBeSkipped(Tai_Label(Current))))
Then GetNextInstruction := True
@ -234,14 +237,15 @@ unit aoptbase;
End;
End;
class function TAOptBase.GetLastInstruction(Current: tai; out Last: tai): Boolean;
class function TAOptBase.GetLastInstruction(Current: tai; out Last: tai; AlsoStopOn: taitypes): Boolean;
Begin
Repeat
Current := Tai(Current.previous);
While Assigned(Current) And
(((Current.typ = ait_Marker) And
Not(Tai_Marker(Current).Kind in [mark_AsmBlockEnd{,mark_NoPropInfoEnd}])) or
(Current.typ In SkipInstr) or
(Current.typ In SkipInstr - AlsoStopOn) or
((Current.typ = ait_label) And
labelCanBeSkipped(Tai_Label(Current)))) Do
Current := Tai(Current.previous);
@ -258,7 +262,7 @@ unit aoptbase;
(Current.typ <> ait_Marker) Or
not(tai_Marker(current).Kind in [mark_NoPropInfoStart,mark_NoPropInfoEnd]);
If Not(Assigned(Current)) or
(Current.typ In SkipInstr) or
(Current.typ In SkipInstr - AlsoStopOn) or
((Current.typ = ait_label) And
labelCanBeSkipped(Tai_Label(Current))) or
((Current.typ = ait_Marker) And

View File

@ -9226,104 +9226,121 @@ unit aoptx86;
if Assigned(hp1) and (hp1.typ = ait_label) then
SkipLabels(hp1,hp1);
if (hp1.typ <> ait_instruction) then
InternalError(2021040720);
case hp1.typ of
ait_regalloc:
if tai_regalloc(hp1).ratype = ra_dealloc then
begin
{ Duplicate the register deallocation... }
hp3:=tai(hp1.getcopy);
if first_assignment = nil then
first_assignment := hp3;
case taicpu(hp1).opcode of
A_JMP:
begin
{ Change the original jump to the new destination }
OrigLabel.decrefs;
taicpu(hp1).oper[0]^.ref^.symbol.increfs;
taicpu(p).loadref(0, taicpu(hp1).oper[0]^.ref^);
asml.InsertBefore(hp3, p);
{ Set p to the first duplicated assignment so it can get optimised if needs be }
if not Assigned(first_assignment) then
InternalError(2021040810)
{ ... but also reallocate it after the jump }
hp3:=tai(hp1.getcopy);
tai_regalloc(hp3).ratype := ra_alloc;
asml.InsertAfter(hp3, p);
end;
ait_instruction:
case taicpu(hp1).opcode of
A_JMP:
begin
{ Change the original jump to the new destination }
OrigLabel.decrefs;
taicpu(hp1).oper[0]^.ref^.symbol.increfs;
taicpu(p).loadref(0, taicpu(hp1).oper[0]^.ref^);
{ Set p to the first duplicated assignment so it can get optimised if needs be }
if not Assigned(first_assignment) then
InternalError(2021040810)
else
p := first_assignment;
Exit;
end;
A_RET:
begin
{ Now change the jump into a RET instruction }
ConvertJumpToRET(p, hp1);
{ Set p to the first duplicated assignment so it can get optimised if needs be }
if not Assigned(first_assignment) then
InternalError(2021040811)
else
p := first_assignment;
Exit;
end;
else
p := first_assignment;
begin
{ Duplicate the MOV instruction }
hp3:=tai(hp1.getcopy);
if first_assignment = nil then
first_assignment := hp3;
Exit;
end;
A_RET:
begin
{ Now change the jump into a RET instruction }
ConvertJumpToRET(p, hp1);
asml.InsertBefore(hp3, p);
{ Set p to the first duplicated assignment so it can get optimised if needs be }
if not Assigned(first_assignment) then
InternalError(2021040811)
else
p := first_assignment;
Exit;
{ Make sure the compiler knows about any final registers written here }
for OperIdx := 0 to taicpu(hp3).ops - 1 do
with taicpu(hp3).oper[OperIdx]^ do
begin
case typ of
top_ref:
begin
if (ref^.base <> NR_NO) and
(getsupreg(ref^.base) <> RS_STACK_POINTER_REG) and
(
(getsupreg(ref^.base) <> RS_FRAME_POINTER_REG) or
(
{ Allow the frame pointer if it's not being used by the procedure as such }
Assigned(current_procinfo) and
(current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
)
)
{$ifdef x86_64} and (ref^.base <> NR_RIP) {$endif x86_64}
then
begin
AllocRegBetween(ref^.base, hp3, p, TmpUsedRegs);
if not Assigned(first_assignment) then
IncludeRegInUsedRegs(ref^.base, UsedRegs);
end;
if (ref^.index <> NR_NO) and
(getsupreg(ref^.index) <> RS_STACK_POINTER_REG) and
(
(getsupreg(ref^.index) <> RS_FRAME_POINTER_REG) or
(
{ Allow the frame pointer if it's not being used by the procedure as such }
Assigned(current_procinfo) and
(current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
)
)
{$ifdef x86_64} and (ref^.index <> NR_RIP) {$endif x86_64} and
(ref^.index <> ref^.base) then
begin
AllocRegBetween(ref^.index, hp3, p, TmpUsedRegs);
if not Assigned(first_assignment) then
IncludeRegInUsedRegs(ref^.index, UsedRegs);
end;
end;
top_reg:
begin
AllocRegBetween(reg, hp3, p, TmpUsedRegs);
if not Assigned(first_assignment) then
IncludeRegInUsedRegs(reg, UsedRegs);
end;
else
;
end;
end;
end;
end;
else
begin
{ Duplicate the MOV instruction }
hp3:=tai(hp1.getcopy);
asml.InsertBefore(hp3, p);
{ Make sure the compiler knows about any final registers written here }
for OperIdx := 0 to taicpu(hp3).ops - 1 do
with taicpu(hp3).oper[OperIdx]^ do
begin
case typ of
top_ref:
begin
if (ref^.base <> NR_NO) and
(getsupreg(ref^.base) <> RS_STACK_POINTER_REG) and
(
(getsupreg(ref^.base) <> RS_FRAME_POINTER_REG) or
(
{ Allow the frame pointer if it's not being used by the procedure as such }
Assigned(current_procinfo) and
(current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
)
)
{$ifdef x86_64} and (ref^.base <> NR_RIP) {$endif x86_64}
then
begin
AllocRegBetween(ref^.base, hp3, p, TmpUsedRegs);
if not Assigned(first_assignment) then
IncludeRegInUsedRegs(ref^.base, UsedRegs);
end;
if (ref^.index <> NR_NO) and
(getsupreg(ref^.index) <> RS_STACK_POINTER_REG) and
(
(getsupreg(ref^.index) <> RS_FRAME_POINTER_REG) or
(
{ Allow the frame pointer if it's not being used by the procedure as such }
Assigned(current_procinfo) and
(current_procinfo.framepointer <> NR_FRAME_POINTER_REG)
)
)
{$ifdef x86_64} and (ref^.index <> NR_RIP) {$endif x86_64} and
(ref^.index <> ref^.base) then
begin
AllocRegBetween(ref^.index, hp3, p, TmpUsedRegs);
if not Assigned(first_assignment) then
IncludeRegInUsedRegs(ref^.index, UsedRegs);
end;
end;
top_reg:
begin
AllocRegBetween(reg, hp3, p, TmpUsedRegs);
if not Assigned(first_assignment) then
IncludeRegInUsedRegs(reg, UsedRegs);
end;
else
;
end;
end;
if first_assignment = nil then
first_assignment := hp3;
end;
InternalError(2021040720);
end;
if not GetNextInstruction(hp1, hp1) then
if not GetNextInstruction(hp1, hp1, [ait_regalloc]) then
{ Should have dropped out earlier }
InternalError(2021040710);
end;