Browse Source

* arm/a64: "OptPass2AND" and "OptPass2CMP" adapted to remove vestigial CMP and TST instructions

J. Gareth "Curious Kit" Moreton 1 year ago
parent
commit
271f69db12
2 changed files with 69 additions and 40 deletions
  1. 21 2
      compiler/arm/aoptcpu.pas
  2. 48 38
      compiler/armgen/aoptarm.pas

+ 21 - 2
compiler/arm/aoptcpu.pas

@@ -2094,6 +2094,26 @@ Implementation
       hp1, hp_last: tai;
     begin
       Result := False;
+      if not GetNextInstructionUsingReg(p, hp1, NR_DEFAULTFLAGS) then
+        Exit;
+
+      if (hp1.typ = ait_label) or
+        (
+          (hp1.typ = ait_instruction) and
+          (taicpu(hp1).condition = C_None) and
+          (
+            RegModifiedByInstruction(NR_DEFAULTFLAGS, hp1) or
+            is_calljmp(taicpu(hp1).opcode)
+          )
+        ) then
+        begin
+          { The comparison is a null operation }
+          DebugMsg(SPeepholeOptimization + 'CMP -> nop', p);
+          RemoveCurrentP(p);
+          Result := True;
+          Exit;
+        end;
+
       {
         change
         <op> reg,x,y
@@ -2103,7 +2123,6 @@ Implementation
       }
       if (taicpu(p).oppostfix = PF_None) and
         (taicpu(p).oper[1]^.val = 0) and
-        GetNextInstruction(p, hp1) and
         { be careful here, following instructions could use other flags
           however after a jump fpc never depends on the value of flags }
         { All above instructions set Z and N according to the following
@@ -2111,7 +2130,7 @@ Implementation
           N := result[31];
           EQ = Z=1; NE = Z=0;
           MI = N=1; PL = N=0; }
-        (MatchInstruction(hp1, A_B, [C_EQ,C_NE,C_MI,C_PL], []) or
+        (MatchInstruction(hp1, [A_B, A_CMP, A_CMN, A_TST, A_TEQ], [C_EQ,C_NE,C_MI,C_PL], []) or
         { mov is also possible, but only if there is no shifter operand, it could be an rxx,
           we are too lazy to check if it is rxx or something else }
         (MatchInstruction(hp1, A_MOV, [C_EQ,C_NE,C_MI,C_PL], []) and (taicpu(hp1).ops=2))) and

+ 48 - 38
compiler/armgen/aoptarm.pas

@@ -1646,51 +1646,61 @@ Implementation
 {$endif AARCH64}
 
         not RegModifiedBetween(NR_DEFAULTFLAGS, p, hp1) and
-        GetNextInstruction(hp1, hp2) and
-        MatchInstruction(hp2, A_B, [C_EQ, C_NE], [PF_None]) then
+        GetNextInstruction(hp1, hp2) then
         begin
-          AllocRegBetween(NR_DEFAULTFLAGS, p, hp1, UsedRegs);
+          if MatchInstruction(hp2, [A_B, A_CMP, A_CMN, A_TST{$ifndef AARCH64}, A_TEQ{$endif not AARCH64}], [C_EQ, C_NE], [PF_None]) then
+            begin
+              AllocRegBetween(NR_DEFAULTFLAGS, p, hp1, UsedRegs);
 
-          WorkingReg := taicpu(p).oper[0]^.reg;
+              WorkingReg := taicpu(p).oper[0]^.reg;
 
-          if RegEndOfLife(WorkingReg, taicpu(hp1)) then
-            begin
-              taicpu(p).opcode := A_TST;
-              taicpu(p).oppostfix := PF_None;
-              taicpu(p).loadreg(0, taicpu(p).oper[1]^.reg);
-              taicpu(p).loadoper(1, taicpu(p).oper[2]^);
-              taicpu(p).ops := 2;
-              DebugMsg(SPeepholeOptimization + 'AND; CMP -> TST', p);
-            end
-          else
-            begin
-              taicpu(p).oppostfix := PF_S;
-              DebugMsg(SPeepholeOptimization + 'AND; CMP -> ANDS', p);
-            end;
+              if RegEndOfLife(WorkingReg, taicpu(hp1)) then
+                begin
+                  taicpu(p).opcode := A_TST;
+                  taicpu(p).oppostfix := PF_None;
+                  taicpu(p).loadreg(0, taicpu(p).oper[1]^.reg);
+                  taicpu(p).loadoper(1, taicpu(p).oper[2]^);
+                  taicpu(p).ops := 2;
+                  DebugMsg(SPeepholeOptimization + 'AND; CMP -> TST', p);
+                end
+              else
+                begin
+                  taicpu(p).oppostfix := PF_S;
+                  DebugMsg(SPeepholeOptimization + 'AND; CMP -> ANDS', p);
+                end;
 
-          RemoveInstruction(hp1);
+              RemoveInstruction(hp1);
 
-          { If a temporary register was used for and/cmp before, we might be
-            able to deallocate the register so it can be used for other
-            optimisations later }
-          if (taicpu(p).opcode = A_TST) and TryRemoveRegAlloc(WorkingReg, p, p) then
-            ExcludeRegFromUsedRegs(WorkingReg, UsedRegs);
+              { If a temporary register was used for and/cmp before, we might be
+                able to deallocate the register so it can be used for other
+                optimisations later }
+              if (taicpu(p).opcode = A_TST) and TryRemoveRegAlloc(WorkingReg, p, p) then
+                ExcludeRegFromUsedRegs(WorkingReg, UsedRegs);
 
-          Result := True;
-          Exit;
+              Result := True;
+              Exit;
+            end
+          else if
+            (hp2.typ = ait_label) or
+            { Conditional comparison instructions have already been covered }
+            RegModifiedByInstruction(NR_DEFAULTFLAGS, hp2) then
+            begin
+              { The comparison is a null operation }
+              if RegEndOfLife(taicpu(p).oper[0]^.reg, taicpu(hp1)) then
+                begin
+                  DebugMsg(SPeepholeOptimization + 'AND; CMP -> nop', p);
+                  RemoveInstruction(hp1);
+                  RemoveCurrentP(p);
+                end
+              else
+                begin
+                  DebugMsg(SPeepholeOptimization + 'CMP -> nop', hp1);
+                  RemoveInstruction(hp1);
+                end;
+              Result := True;
+              Exit;
+            end;
         end;
-
-      {
-        change
-        and reg1, ...
-        mov reg2, reg1
-        to
-        and reg2, ...
-      }
-      if GetNextInstructionUsingReg(p, hp1, taicpu(p).oper[0]^.reg) and
-         (taicpu(p).ops>=3) and
-         RemoveSuperfluousMove(p, hp1, 'DataMov2Data') then
-        Result:=true;
     end;