From 7afe762d22fe99964d707d021090ee3349f5081c Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 7 May 2017 12:45:48 +0000 Subject: [PATCH] * factored out OptPass2Jcc assembler optimization * OptPass2Jcc now used by x86-64 as well * remove orphaned alignments if the label is not used anymore after cmov is used git-svn-id: trunk@36143 - --- compiler/i386/aoptcpu.pas | 195 +------------------------------- compiler/x86/aoptx86.pas | 216 +++++++++++++++++++++++++++++++++++- compiler/x86_64/aoptcpu.pas | 2 + 3 files changed, 218 insertions(+), 195 deletions(-) diff --git a/compiler/i386/aoptcpu.pas b/compiler/i386/aoptcpu.pas index 379fa91b76..f66c2defc9 100644 --- a/compiler/i386/aoptcpu.pas +++ b/compiler/i386/aoptcpu.pas @@ -1753,22 +1753,6 @@ procedure TCPUAsmOptimizer.PeepHoleOptPass2; end; {$endif DEBUG_AOPTCPU} - function CanBeCMOV(p : tai) : boolean; - begin - CanBeCMOV:=assigned(p) and (p.typ=ait_instruction) and - (taicpu(p).opcode=A_MOV) and - (taicpu(p).opsize in [S_L,S_W]) and - ((taicpu(p).oper[0]^.typ = top_reg) - { we can't use cmov ref,reg because - ref could be nil and cmov still throws an exception - if ref=nil but the mov isn't done (FK) - or ((taicpu(p).oper[0]^.typ = top_ref) and - (taicpu(p).oper[0]^.ref^.refaddr = addr_no)) - } - ) and - (taicpu(p).oper[1]^.typ in [top_reg]); - end; - var p,hp1,hp2,hp3: tai; l : longint; @@ -1791,183 +1775,8 @@ begin end; case taicpu(p).opcode Of A_Jcc: - begin - { jb @@1 cmc - inc/dec operand --> adc/sbb operand,0 - @@1: - - ... and ... - - jnb @@1 - inc/dec operand --> adc/sbb operand,0 - @@1: } - if GetNextInstruction(p,hp1) and (hp1.typ=ait_instruction) and - GetNextInstruction(hp1,hp2) and (hp2.typ=ait_label) and - (Tasmlabel(Taicpu(p).oper[0]^.ref^.symbol)=Tai_label(hp2).labsym) then - begin - carryadd_opcode:=A_NONE; - if Taicpu(p).condition in [C_NAE,C_B] then - begin - if Taicpu(hp1).opcode=A_INC then - carryadd_opcode:=A_ADC; - if Taicpu(hp1).opcode=A_DEC then - carryadd_opcode:=A_SBB; - if carryadd_opcode<>A_NONE then - begin - Taicpu(p).clearop(0); - Taicpu(p).ops:=0; - Taicpu(p).is_jmp:=false; - Taicpu(p).opcode:=A_CMC; - Taicpu(p).condition:=C_NONE; - Taicpu(hp1).ops:=2; - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); - Taicpu(hp1).loadconst(0,0); - Taicpu(hp1).opcode:=carryadd_opcode; - continue; - end; - end; - if Taicpu(p).condition in [C_AE,C_NB] then - begin - if Taicpu(hp1).opcode=A_INC then - carryadd_opcode:=A_ADC; - if Taicpu(hp1).opcode=A_DEC then - carryadd_opcode:=A_SBB; - if carryadd_opcode<>A_NONE then - begin - asml.remove(p); - p.free; - Taicpu(hp1).ops:=2; - Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); - Taicpu(hp1).loadconst(0,0); - Taicpu(hp1).opcode:=carryadd_opcode; - p:=hp1; - continue; - end; - end; - end; - if CPUX86_HAS_CMOV in cpu_capabilities[current_settings.cputype] then - begin - { check for - jCC xxx - - xxx: - } - l:=0; - GetNextInstruction(p, hp1); - while assigned(hp1) and - CanBeCMOV(hp1) and - { stop on labels } - not(hp1.typ=ait_label) do - begin - inc(l); - GetNextInstruction(hp1,hp1); - end; - if assigned(hp1) then - begin - if FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol),hp1) then - begin - if (l<=4) and (l>0) then - begin - condition:=inverse_cond(taicpu(p).condition); - hp2:=p; - GetNextInstruction(p,hp1); - p:=hp1; - repeat - taicpu(hp1).opcode:=A_CMOVcc; - taicpu(hp1).condition:=condition; - GetNextInstruction(hp1,hp1); - until not(assigned(hp1)) or - not(CanBeCMOV(hp1)); - { wait with removing else GetNextInstruction could - ignore the label if it was the only usage in the - jump moved away } - tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).decrefs; - asml.remove(hp2); - hp2.free; - continue; - end; - end - else - begin - { check further for - jCC xxx - - jmp yyy - xxx: - - yyy: - } - { hp2 points to jmp yyy } - hp2:=hp1; - { skip hp1 to xxx } - GetNextInstruction(hp1, hp1); - if assigned(hp2) and - assigned(hp1) and - (l<=3) and - (hp2.typ=ait_instruction) and - (taicpu(hp2).is_jmp) and - (taicpu(hp2).condition=C_None) and - { real label and jump, no further references to the - label are allowed } - (tasmlabel(taicpu(p).oper[0]^.ref^.symbol).getrefs=1) and - FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol),hp1) then - begin - l:=0; - { skip hp1 to } - GetNextInstruction(hp1, hp1); - while assigned(hp1) and - CanBeCMOV(hp1) do - begin - inc(l); - GetNextInstruction(hp1, hp1); - end; - { hp1 points to yyy: } - if assigned(hp1) and - FindLabel(tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol),hp1) then - begin - condition:=inverse_cond(taicpu(p).condition); - GetNextInstruction(p,hp1); - hp3:=p; - p:=hp1; - repeat - taicpu(hp1).opcode:=A_CMOVcc; - taicpu(hp1).condition:=condition; - GetNextInstruction(hp1,hp1); - until not(assigned(hp1)) or - not(CanBeCMOV(hp1)); - { hp2 is still at jmp yyy } - GetNextInstruction(hp2,hp1); - { hp2 is now at xxx: } - condition:=inverse_cond(condition); - GetNextInstruction(hp1,hp1); - { hp1 is now at } - repeat - taicpu(hp1).opcode:=A_CMOVcc; - taicpu(hp1).condition:=condition; - GetNextInstruction(hp1,hp1); - until not(assigned(hp1)) or - not(CanBeCMOV(hp1)); - { - asml.remove(hp1.next) - hp1.next.free; - asml.remove(hp1); - hp1.free; - } - { remove jCC } - tasmlabel(taicpu(hp3).oper[0]^.ref^.symbol).decrefs; - asml.remove(hp3); - hp3.free; - { remove jmp } - tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).decrefs; - asml.remove(hp2); - hp2.free; - continue; - end; - end; - end; - end; - end; - end; + if OptPass2Jcc(p) then + continue; A_FSTP,A_FISTP: if DoFpuLoadStoreOpt(p) then continue; diff --git a/compiler/x86/aoptx86.pas b/compiler/x86/aoptx86.pas index 2aab96d4a7..0720d0ad45 100644 --- a/compiler/x86/aoptx86.pas +++ b/compiler/x86/aoptx86.pas @@ -56,6 +56,7 @@ unit aoptx86; function OptPass2MOV(var p : tai) : boolean; function OptPass2Imul(var p : tai) : boolean; function OptPass2Jmp(var p : tai) : boolean; + function OptPass2Jcc(var p : tai) : boolean; procedure DebugMsg(const s : string; p : tai);inline; @@ -87,8 +88,9 @@ unit aoptx86; implementation uses - cutils, - verbose, + cutils,verbose, + globals, + cpuinfo, procinfo, aasmbase, aoptutils, @@ -1411,6 +1413,216 @@ unit aoptx86; end; + function CanBeCMOV(p : tai) : boolean; + begin + CanBeCMOV:=assigned(p) and + MatchInstruction(p,A_MOV,[S_W,S_L,S_Q]) and + { we can't use cmov ref,reg because + ref could be nil and cmov still throws an exception + if ref=nil but the mov isn't done (FK) + or ((taicpu(p).oper[0]^.typ = top_ref) and + (taicpu(p).oper[0]^.ref^.refaddr = addr_no)) + } + MatchOpType(p,top_reg,top_reg); + end; + + + function TX86AsmOptimizer.OptPass2Jcc(var p : tai) : boolean; + var + hp1,hp2,hp3: tai; + carryadd_opcode : TAsmOp; + l : Longint; + condition : TAsmCond; + begin + { jb @@1 cmc + inc/dec operand --> adc/sbb operand,0 + @@1: + + ... and ... + + jnb @@1 + inc/dec operand --> adc/sbb operand,0 + @@1: } + result:=false; + if GetNextInstruction(p,hp1) and (hp1.typ=ait_instruction) and + GetNextInstruction(hp1,hp2) and (hp2.typ=ait_label) and + (Tasmlabel(Taicpu(p).oper[0]^.ref^.symbol)=Tai_label(hp2).labsym) then + begin + carryadd_opcode:=A_NONE; + if Taicpu(p).condition in [C_NAE,C_B] then + begin + if Taicpu(hp1).opcode=A_INC then + carryadd_opcode:=A_ADC; + if Taicpu(hp1).opcode=A_DEC then + carryadd_opcode:=A_SBB; + if carryadd_opcode<>A_NONE then + begin + Taicpu(p).clearop(0); + Taicpu(p).ops:=0; + Taicpu(p).is_jmp:=false; + Taicpu(p).opcode:=A_CMC; + Taicpu(p).condition:=C_NONE; + Taicpu(hp1).ops:=2; + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); + Taicpu(hp1).loadconst(0,0); + Taicpu(hp1).opcode:=carryadd_opcode; + result:=true; + exit; + end; + end; + if Taicpu(p).condition in [C_AE,C_NB] then + begin + if Taicpu(hp1).opcode=A_INC then + carryadd_opcode:=A_ADC; + if Taicpu(hp1).opcode=A_DEC then + carryadd_opcode:=A_SBB; + if carryadd_opcode<>A_NONE then + begin + asml.remove(p); + p.free; + Taicpu(hp1).ops:=2; + Taicpu(hp1).loadoper(1,Taicpu(hp1).oper[0]^); + Taicpu(hp1).loadconst(0,0); + Taicpu(hp1).opcode:=carryadd_opcode; + p:=hp1; + result:=true; + exit; + end; + end; + end; + if CPUX86_HAS_CMOV in cpu_capabilities[current_settings.cputype] then + begin + { check for + jCC xxx + + xxx: + } + l:=0; + GetNextInstruction(p, hp1); + while assigned(hp1) and + CanBeCMOV(hp1) and + { stop on labels } + not(hp1.typ=ait_label) do + begin + inc(l); + GetNextInstruction(hp1,hp1); + end; + if assigned(hp1) then + begin + if FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol),hp1) then + begin + if (l<=4) and (l>0) then + begin + condition:=inverse_cond(taicpu(p).condition); + hp2:=p; + GetNextInstruction(p,hp1); + p:=hp1; + repeat + taicpu(hp1).opcode:=A_CMOVcc; + taicpu(hp1).condition:=condition; + GetNextInstruction(hp1,hp1); + until not(assigned(hp1)) or + not(CanBeCMOV(hp1)); + { wait with removing else GetNextInstruction could + ignore the label if it was the only usage in the + jump moved away } + tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).decrefs; + { if the label refs. reach zero, remove any alignment before the label } + if (hp1.typ=ait_align) and (tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).getrefs=0) then + begin + asml.Remove(hp1); + hp1.Free; + end; + asml.remove(hp2); + hp2.free; + result:=true; + exit; + end; + end + else + begin + { check further for + jCC xxx + + jmp yyy + xxx: + + yyy: + } + { hp2 points to jmp yyy } + hp2:=hp1; + { skip hp1 to xxx } + GetNextInstruction(hp1, hp1); + if assigned(hp2) and + assigned(hp1) and + (l<=3) and + (hp2.typ=ait_instruction) and + (taicpu(hp2).is_jmp) and + (taicpu(hp2).condition=C_None) and + { real label and jump, no further references to the + label are allowed } + (tasmlabel(taicpu(p).oper[0]^.ref^.symbol).getrefs=1) and + FindLabel(tasmlabel(taicpu(p).oper[0]^.ref^.symbol),hp1) then + begin + l:=0; + { skip hp1 to } + GetNextInstruction(hp1, hp1); + while assigned(hp1) and + CanBeCMOV(hp1) do + begin + inc(l); + GetNextInstruction(hp1, hp1); + end; + { hp1 points to yyy: } + if assigned(hp1) and + FindLabel(tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol),hp1) then + begin + condition:=inverse_cond(taicpu(p).condition); + GetNextInstruction(p,hp1); + hp3:=p; + p:=hp1; + repeat + taicpu(hp1).opcode:=A_CMOVcc; + taicpu(hp1).condition:=condition; + GetNextInstruction(hp1,hp1); + until not(assigned(hp1)) or + not(CanBeCMOV(hp1)); + { hp2 is still at jmp yyy } + GetNextInstruction(hp2,hp1); + { hp2 is now at xxx: } + condition:=inverse_cond(condition); + GetNextInstruction(hp1,hp1); + { hp1 is now at } + repeat + taicpu(hp1).opcode:=A_CMOVcc; + taicpu(hp1).condition:=condition; + GetNextInstruction(hp1,hp1); + until not(assigned(hp1)) or + not(CanBeCMOV(hp1)); + { + asml.remove(hp1.next) + hp1.next.free; + asml.remove(hp1); + hp1.free; + } + { remove jCC } + tasmlabel(taicpu(hp3).oper[0]^.ref^.symbol).decrefs; + asml.remove(hp3); + hp3.free; + { remove jmp } + tasmlabel(taicpu(hp2).oper[0]^.ref^.symbol).decrefs; + asml.remove(hp2); + hp2.free; + result:=true; + exit; + end; + end; + end; + end; + end; + end; + + function TX86AsmOptimizer.OptPass1AND(var p : tai) : boolean; var hp1 : tai; diff --git a/compiler/x86_64/aoptcpu.pas b/compiler/x86_64/aoptcpu.pas index 6c503b0285..46fdd52b20 100644 --- a/compiler/x86_64/aoptcpu.pas +++ b/compiler/x86_64/aoptcpu.pas @@ -359,6 +359,8 @@ end; Result:=OptPass2Imul(p); A_JMP: Result:=OptPass2Jmp(p); + A_Jcc: + Result:=OptPass2Jcc(p); end; end; end;