Browse Source

New MOV optimisation that helps reduce instruction count and memory accesses

J. Gareth "Curious Kit" Moreton 3 years ago
parent
commit
bb49c190af
1 changed files with 68 additions and 0 deletions
  1. 68 0
      compiler/x86/aoptx86.pas

+ 68 - 0
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) }