Browse Source

* patch by J. Gareth Moreton: Memory CMP optimisation, resolves #38907

git-svn-id: trunk@49382 -
florian 4 years ago
parent
commit
6f482952de
1 changed files with 64 additions and 15 deletions
  1. 64 15
      compiler/x86/aoptx86.pas

+ 64 - 15
compiler/x86/aoptx86.pas

@@ -2819,24 +2819,73 @@ unit aoptx86;
             Result:=true;
             exit;
           end;
-        if MatchOpType(taicpu(p),top_reg,top_ref) and
-          MatchInstruction(hp1,A_CMP,A_TEST,[taicpu(p).opsize]) and
-          (taicpu(hp1).oper[1]^.typ = top_ref) and
-           RefsEqual(taicpu(p).oper[1]^.ref^, taicpu(hp1).oper[1]^.ref^) then
+        if MatchInstruction(hp1,A_CMP,A_TEST,[taicpu(p).opsize]) then
           begin
-            { change
-                mov reg1, mem1
-                test/cmp x, mem1
+            if MatchOpType(taicpu(p),top_reg,top_ref) and
+              (taicpu(hp1).oper[1]^.typ = top_ref) and
+              RefsEqual(taicpu(p).oper[1]^.ref^, taicpu(hp1).oper[1]^.ref^) then
+              begin
+                { change
+                    mov reg1, mem1
+                    test/cmp x, mem1
 
-                to
+                    to
 
-                mov reg1, mem1
-                test/cmp x, reg1
-            }
-            taicpu(hp1).loadreg(1,taicpu(p).oper[0]^.reg);
-            DebugMsg(SPeepholeOptimization + 'MovTestCmp2MovTestCmp 1',hp1);
-            AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,usedregs);
-            exit;
+                    mov reg1, mem1
+                    test/cmp x, reg1
+                }
+                taicpu(hp1).loadreg(1,taicpu(p).oper[0]^.reg);
+                DebugMsg(SPeepholeOptimization + 'MovTestCmp2MovTestCmp 1',hp1);
+                AllocRegBetween(taicpu(p).oper[0]^.reg,p,hp1,usedregs);
+                Result := True;
+                Exit;
+              end;
+
+            if MatchOpType(taicpu(p),top_ref,top_reg) and
+              { The x86 assemblers have difficulty comparing values against absolute addresses }
+              (taicpu(p).oper[0]^.ref^.refaddr in [addr_no, addr_pic, addr_pic_no_got]) and
+              (taicpu(hp1).oper[0]^.typ <> top_ref) and
+              MatchOperand(taicpu(hp1).oper[1]^, taicpu(p).oper[1]^.reg) and
+              (
+                (
+                  (taicpu(hp1).opcode = A_TEST)
+                ) or (
+                  (taicpu(hp1).opcode = A_CMP) and
+                  { A sanity check more than anything }
+                  not MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[1]^.reg)
+                )
+              ) then
+              begin
+                { change
+                    mov      mem, %reg
+                    cmp/test x,   %reg / test %reg,%reg
+                    (reg deallocated)
+
+                    to
+
+                    cmp/test x,   mem  / cmp  0,   mem
+                }
+                TransferUsedRegs(TmpUsedRegs);
+                UpdateUsedRegs(TmpUsedRegs, tai(p.Next));
+                if not RegUsedAfterInstruction(taicpu(p).oper[1]^.reg, hp1, TmpUsedRegs) then
+                  begin
+                    { Convert test %reg,%reg or test $-1,%reg to cmp $0,mem }
+                    if (taicpu(hp1).opcode = A_TEST) and
+                      (
+                        MatchOperand(taicpu(hp1).oper[0]^, taicpu(p).oper[1]^.reg) or
+                        MatchOperand(taicpu(hp1).oper[0]^, -1)
+                      ) then
+                      begin
+                        taicpu(hp1).opcode := A_CMP;
+                        taicpu(hp1).loadconst(0, 0);
+                      end;
+                    taicpu(hp1).loadref(1, taicpu(p).oper[0]^.ref^);
+                    DebugMsg(SPeepholeOptimization + 'MOV/CMP -> CMP (memory check)', p);
+                    RemoveCurrentP(p, hp1);
+                    Result := True;
+                    Exit;
+                  end;
+              end;
           end;
 
         if MatchInstruction(hp1,A_LEA,[S_L{$ifdef x86_64},S_Q{$endif x86_64}]) and