Browse Source

* Patch by J. Gareth "Kit" Moreton (issue #39343). x86 peephole
optimization of conditions which are always true or false.

Yuriy Sydorov 3 years ago
parent
commit
6007ceb908
1 changed files with 115 additions and 1 deletions
  1. 115 1
      compiler/x86/aoptx86.pas

+ 115 - 1
compiler/x86/aoptx86.pas

@@ -2194,6 +2194,7 @@ unit aoptx86;
     function TX86AsmOptimizer.OptPass1MOV(var p : tai) : boolean;
     function TX86AsmOptimizer.OptPass1MOV(var p : tai) : boolean;
     var
     var
       hp1, hp2, hp3: tai;
       hp1, hp2, hp3: tai;
+      DoOptimisation, TempBool: Boolean;
 
 
       procedure convert_mov_value(signed_movop: tasmop; max_value: tcgint); inline;
       procedure convert_mov_value(signed_movop: tasmop; max_value: tcgint); inline;
         begin
         begin
@@ -2622,7 +2623,120 @@ unit aoptx86;
             }
             }
             TransferUsedRegs(TmpUsedRegs);
             TransferUsedRegs(TmpUsedRegs);
             UpdateUsedRegs(TmpUsedRegs, tai(p.Next));
             UpdateUsedRegs(TmpUsedRegs, tai(p.Next));
-            if not (RegInUsedRegs(NR_DEFAULTFLAGS, TmpUsedRegs)) then
+            DoOptimisation := True;
+
+            { Even if the flags are used, we might be able to do the optimisation
+              if the conditions are predictable }
+            if RegInUsedRegs(NR_DEFAULTFLAGS, TmpUsedRegs) then
+              begin
+                { Only perform if ### = %reg (the same register) or equal to 0,
+                  so %reg is guaranteed to still have a value of zero }
+                if MatchOperand(taicpu(hp1).oper[0]^, 0) or
+                  MatchOperand(taicpu(hp1).oper[0]^, taicpu(hp1).oper[1]^.reg) then
+                  begin
+                    hp2 := hp1;
+                    UpdateUsedRegs(TmpUsedRegs, tai(hp1.Next));
+                    while RegInUsedRegs(NR_DEFAULTFLAGS, TmpUsedRegs) and
+                      GetNextInstruction(hp2, hp3) do
+                      begin
+                        { Don't continue modifying if the flags state is getting changed }
+                        if RegModifiedByInstruction(NR_DEFAULTFLAGS, hp3) then
+                          Break;
+
+                        UpdateUsedRegs(TmpUsedRegs, tai(hp3.Next));
+                        if MatchInstruction(hp3, A_Jcc, A_SETcc, A_CMOVcc, []) then
+                          begin
+
+                            if condition_in(C_E, taicpu(hp3).condition) or (taicpu(hp3).condition in [C_NC, C_NS, C_NO]) then
+                              begin
+                                { Condition is always true }
+                                case taicpu(hp3).opcode of
+                                  A_Jcc:
+                                    begin
+                                      DebugMsg(SPeepholeOptimization + 'Condition is always true (jump made unconditional)', hp3);
+                                      { Check for jump shortcuts before we destroy the condition }
+                                      DoJumpOptimizations(hp3, TempBool);
+                                      MakeUnconditional(taicpu(hp3));
+                                      Result := True;
+                                    end;
+                                  A_CMOVcc:
+                                    begin
+                                      DebugMsg(SPeepholeOptimization + 'Condition is always true (CMOVcc -> MOV)', hp3);
+                                      taicpu(hp3).opcode := A_MOV;
+                                      taicpu(hp3).condition := C_None;
+                                      Result := True;
+                                    end;
+                                  A_SETcc:
+                                    begin
+                                      DebugMsg(SPeepholeOptimization + 'Condition is always true (changed to MOV 1)', hp3);
+                                      { Convert "set(c) %reg" instruction to "movb 1,%reg" }
+                                      taicpu(hp3).opcode := A_MOV;
+                                      taicpu(hp3).ops := 2;
+                                      taicpu(hp3).condition := C_None;
+                                      taicpu(hp3).opsize := S_B;
+                                      taicpu(hp3).loadreg(1,taicpu(hp3).oper[0]^.reg);
+                                      taicpu(hp3).loadconst(0, 1);
+                                      Result := True;
+                                    end;
+                                  else
+                                    InternalError(2021090701);
+                                end;
+                              end
+                            else if (taicpu(hp3).condition in [C_A, C_B, C_C, C_G, C_L, C_NE, C_NZ, C_O, C_S]) then
+                              begin
+                                { Condition is always false }
+                                case taicpu(hp3).opcode of
+                                  A_Jcc:
+                                    begin
+                                      DebugMsg(SPeepholeOptimization + 'Condition is always false (jump removed)', hp3);
+                                      TAsmLabel(taicpu(hp3).oper[0]^.ref^.symbol).decrefs;
+                                      RemoveInstruction(hp3);
+                                      Result := True;
+                                      { Since hp3 was deleted, hp2 must not be updated }
+                                      Continue;
+                                    end;
+                                  A_CMOVcc:
+                                    begin
+                                      DebugMsg(SPeepholeOptimization + 'Condition is always false (conditional load removed)', hp3);
+                                      RemoveInstruction(hp3);
+                                      Result := True;
+                                      { Since hp3 was deleted, hp2 must not be updated }
+                                      Continue;
+                                    end;
+                                  A_SETcc:
+                                    begin
+                                      DebugMsg(SPeepholeOptimization + 'Condition is always false (changed to MOV 0)', hp3);
+                                      { Convert "set(c) %reg" instruction to "movb 0,%reg" }
+                                      taicpu(hp3).opcode := A_MOV;
+                                      taicpu(hp3).ops := 2;
+                                      taicpu(hp3).condition := C_None;
+                                      taicpu(hp3).opsize := S_B;
+                                      taicpu(hp3).loadreg(1,taicpu(hp3).oper[0]^.reg);
+                                      taicpu(hp3).loadconst(0, 0);
+                                      Result := True;
+                                    end;
+                                  else
+                                    InternalError(2021090702);
+                                end;
+                              end
+                            else
+                              { Uncertain what to do - don't optimise (although optimise other conditional statements if present) }
+                              DoOptimisation := False;
+                          end;
+
+                        hp2 := hp3;
+                      end;
+
+                    { Flags are still in use - don't optimise }
+                    if DoOptimisation and RegInUsedRegs(NR_DEFAULTFLAGS, TmpUsedRegs) then
+                      DoOptimisation := False;
+
+                  end
+                else
+                  DoOptimisation := False;
+              end;
+
+            if DoOptimisation then
               begin
               begin
 {$ifdef x86_64}
 {$ifdef x86_64}
                 { OR only supports 32-bit sign-extended constants for 64-bit
                 { OR only supports 32-bit sign-extended constants for 64-bit