From fb66369a3bcffdf7d2a96cffe8c633b2ecd12182 Mon Sep 17 00:00:00 2001 From: "J. Gareth \"Curious Kit\" Moreton" Date: Sat, 22 Oct 2022 22:24:39 +0100 Subject: [PATCH] * x86: CheckJumpMovTransferOpt now also copies over register deallocations to allow better optimisations --- compiler/aasmtai.pas | 2 + compiler/aoptbase.pas | 24 +++-- compiler/x86/aoptx86.pas | 195 +++++++++++++++++++++------------------ 3 files changed, 122 insertions(+), 99 deletions(-) diff --git a/compiler/aasmtai.pas b/compiler/aasmtai.pas index ed77040674..aca79b0c16 100644 --- a/compiler/aasmtai.pas +++ b/compiler/aasmtai.pas @@ -108,6 +108,8 @@ interface ait_eabi_attribute ); + taitypes = set of taitype; + taiconst_type = ( aitconst_128bit, aitconst_64bit, diff --git a/compiler/aoptbase.pas b/compiler/aoptbase.pas index 8cb542081d..42c3dc1680 100644 --- a/compiler/aoptbase.pas +++ b/compiler/aoptbase.pas @@ -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 diff --git a/compiler/x86/aoptx86.pas b/compiler/x86/aoptx86.pas index abf75a58b8..54c48ff48f 100644 --- a/compiler/x86/aoptx86.pas +++ b/compiler/x86/aoptx86.pas @@ -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;