From bb49c190afdd16da94cae4c6fdbc1e5ae4f8aa7f Mon Sep 17 00:00:00 2001 From: "J. Gareth \"Curious Kit\" Moreton" Date: Sun, 9 Jan 2022 08:38:21 +0000 Subject: [PATCH] New MOV optimisation that helps reduce instruction count and memory accesses --- compiler/x86/aoptx86.pas | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/compiler/x86/aoptx86.pas b/compiler/x86/aoptx86.pas index 6730537a9c..55baf4d345 100644 --- a/compiler/x86/aoptx86.pas +++ b/compiler/x86/aoptx86.pas @@ -3517,6 +3517,74 @@ unit aoptx86; end; { mov x,reg1; mov y,reg1 -> mov y,reg1 is handled by the Mov2Nop 5 optimisation } + + { Change: + movl %reg1,%reg2 + movl x(%reg1),%reg1 (If something other than %reg1 is written to, DeepMOVOpt would have caught it) + movl x(%reg2),%regX (%regX can be %reg2 or something else) + To: + movl %reg1,%reg2 (if %regX = %reg2, then remove this instruction) + movl x(%reg1),%reg1 + movl %reg1,%regX + } + if MatchOpType(taicpu(p), top_reg, top_reg) then + begin + CurrentReg := taicpu(p).oper[0]^.reg; + ActiveReg := taicpu(p).oper[1]^.reg; + + if (taicpu(hp1).oper[0]^.typ = top_ref) { The other operand will be a register } and + (taicpu(hp1).oper[1]^.reg = CurrentReg) and + RegInRef(CurrentReg, taicpu(hp1).oper[0]^.ref^) and + GetNextInstruction(hp1, hp2) and + MatchInstruction(hp2, A_MOV, [taicpu(p).opsize]) and + (taicpu(hp2).oper[0]^.typ = top_ref) { The other operand will be a register } then + begin + SourceRef := taicpu(hp2).oper[0]^.ref^; + if RegInRef(ActiveReg, SourceRef) and + { If %reg1 also appears in the second reference, then it will + not refer to the same memory block as the first reference } + not RegInRef(CurrentReg, SourceRef) then + begin + { Check to see if the references match if %reg2 is changed to %reg1 } + if SourceRef.base = ActiveReg then + SourceRef.base := CurrentReg; + + if SourceRef.index = ActiveReg then + SourceRef.index := CurrentReg; + + { RefsEqual also checks to ensure both references are non-volatile } + if RefsEqual(taicpu(hp1).oper[0]^.ref^, SourceRef) then + begin + taicpu(hp2).loadreg(0, CurrentReg); + + DebugMsg(SPeepholeOptimization + 'Optimised register duplication and memory read (MovMovMov2MovMovMov)', p); + Result := True; + if taicpu(hp2).oper[1]^.reg = ActiveReg then + begin + DebugMsg(SPeepholeOptimization + 'Mov2Nop 5a done', p); + RemoveCurrentP(p, hp1); + Exit; + end + else + begin + { Check to see if %reg2 is no longer in use } + TransferUsedRegs(TmpUsedRegs); + UpdateUsedRegs(TmpUsedRegs, tai(p.Next)); + UpdateUsedRegs(TmpUsedRegs, tai(hp1.Next)); + + if not RegUsedAfterInstruction(ActiveReg, hp2, TmpUsedRegs) then + begin + DebugMsg(SPeepholeOptimization + 'Mov2Nop 5b done', p); + RemoveCurrentP(p, hp1); + Exit; + end; + end; + { If we reach this point, p and hp1 weren't actually modified, + so we can do a bit more work on this pass } + end; + end; + end; + end; end; { search further than the next instruction for a mov (as long as it's not a jump) }