瀏覽代碼

Bolder OptPass2Movx optimisations, including a simplification fix

J. Gareth "Curious Kit" Moreton 3 年之前
父節點
當前提交
f02b7508de
共有 1 個文件被更改,包括 84 次插入27 次删除
  1. 84 27
      compiler/x86/aoptx86.pas

+ 84 - 27
compiler/x86/aoptx86.pas

@@ -7954,7 +7954,7 @@ unit aoptx86;
 
         { Data flow analysis }
         TestValMin, TestValMax: TCgInt;
-        SmallerOverflow: Boolean;
+        SmallerOverflow, BitwiseOnly, OrXorUsed: Boolean;
 
       begin
         Result := False;
@@ -8000,6 +8000,8 @@ unit aoptx86;
         TrySmaller := S_NO;
         SmallerOverflow := False;
         RegChanged := False;
+        BitwiseOnly := True;
+        OrXorUsed := False;
 
         hp1 := p;
 
@@ -8118,9 +8120,7 @@ unit aoptx86;
                     end;
                 end;
 
-              { OR and XOR are not included because they can too easily fool
-                the data flow analysis (they can cause non-linear behaviour) }
-              A_ADD,A_SUB,A_AND,A_SHL,A_SHR:
+              A_ADD,A_SUB,A_AND,A_OR,A_XOR,A_SHL,A_SHR:
                 begin
                   if
                     (taicpu(hp1).oper[1]^.typ <> top_reg) or
@@ -8153,29 +8153,49 @@ unit aoptx86;
                     ) then
                     Break;
 
+                  { Only process OR and XOR if there are only bitwise operations,
+                    since otherwise they can too easily fool the data flow
+                    analysis (they can cause non-linear behaviour) }
+
                   case taicpu(hp1).opcode of
                     A_ADD:
-                      if (taicpu(hp1).oper[0]^.typ = top_reg) then
-                        begin
-                          TestValMin := TestValMin * 2;
-                          TestValMax := TestValMax * 2;
-                        end
-                      else
-                        begin
-                          TestValMin := TestValMin + taicpu(hp1).oper[0]^.val;
-                          TestValMax := TestValMax + taicpu(hp1).oper[0]^.val;
-                        end;
+                      begin
+                        if OrXorUsed then
+                          { Too high a risk of non-linear behaviour that breaks DFA here }
+                          Break
+                        else
+                          BitwiseOnly := False;
+
+                        if (taicpu(hp1).oper[0]^.typ = top_reg) then
+                          begin
+                            TestValMin := TestValMin * 2;
+                            TestValMax := TestValMax * 2;
+                          end
+                        else
+                          begin
+                            TestValMin := TestValMin + taicpu(hp1).oper[0]^.val;
+                            TestValMax := TestValMax + taicpu(hp1).oper[0]^.val;
+                          end;
+                      end;
                     A_SUB:
-                      if (taicpu(hp1).oper[0]^.typ = top_reg) then
-                        begin
-                          TestValMin := 0;
-                          TestValMax := 0;
-                        end
-                      else
-                        begin
-                          TestValMin := TestValMin - taicpu(hp1).oper[0]^.val;
-                          TestValMax := TestValMax - taicpu(hp1).oper[0]^.val;
-                        end;
+                      begin
+                        if OrXorUsed then
+                          { Too high a risk of non-linear behaviour that breaks DFA here }
+                          Break
+                        else
+                          BitwiseOnly := False;
+
+                        if (taicpu(hp1).oper[0]^.typ = top_reg) then
+                          begin
+                            TestValMin := 0;
+                            TestValMax := 0;
+                          end
+                        else
+                          begin
+                            TestValMin := TestValMin - taicpu(hp1).oper[0]^.val;
+                            TestValMax := TestValMax - taicpu(hp1).oper[0]^.val;
+                          end;
+                      end;
                     A_AND:
                       if (taicpu(hp1).oper[0]^.typ = top_const) then
                         begin
@@ -8211,6 +8231,26 @@ unit aoptx86;
                           TestValMin := TestValMin and taicpu(hp1).oper[0]^.val;
                           TestValMax := TestValMax and taicpu(hp1).oper[0]^.val;
                         end;
+                    A_OR:
+                      begin
+                        if not BitwiseOnly then
+                          Break;
+
+                        OrXorUsed := True;
+
+                        TestValMin := TestValMin or taicpu(hp1).oper[0]^.val;
+                        TestValMax := TestValMax or taicpu(hp1).oper[0]^.val;
+                      end;
+                    A_XOR:
+                      begin
+                        if not BitwiseOnly then
+                          Break;
+
+                        OrXorUsed := True;
+
+                        TestValMin := TestValMin xor taicpu(hp1).oper[0]^.val;
+                        TestValMax := TestValMax xor taicpu(hp1).oper[0]^.val;
+                      end;
                     A_SHL:
                       begin
                         TestValMin := TestValMin shl taicpu(hp1).oper[0]^.val;
@@ -8469,8 +8509,6 @@ unit aoptx86;
                           hp2 := p;
                           repeat
 
-                            UpdateUsedRegs(TmpUsedRegs, tai(hp2.next));
-
                             { Explicitly check for the excluded register (don't include the first
                               instruction as it may be reading from here }
                             if ((p <> hp2) and (RegInInstruction(taicpu(hp1).oper[1]^.reg, hp2))) or
@@ -8480,12 +8518,31 @@ unit aoptx86;
                                 Break;
                               end;
 
+                            UpdateUsedRegs(TmpUsedRegs, tai(hp2.next));
+
                             if not GetNextInstruction(hp2, hp2) then
                               InternalError(2020112340);
 
                           until (hp2 = hp1);
 
-                          if not RegInUse and not RegUsedAfterInstruction(ThisReg, hp1, TmpUsedRegs) then
+                          if not RegInUse and RegUsedAfterInstruction(ThisReg, hp1, TmpUsedRegs) then
+                            begin
+                              RegInUse := True;
+
+                              { We might still be able to get away with this }
+                              if GetNextInstructionUsingReg(hp1, hp2, ThisReg) and
+                                (hp2.typ = ait_instruction) and
+                                (
+                                  { Under -O1 and -O2, GetNextInstructionUsingReg may return an
+                                    instruction that doesn't actually contain ThisReg }
+                                  (cs_opt_level3 in current_settings.optimizerswitches) or
+                                  RegInInstruction(ThisReg, hp2)
+                                ) and
+                                RegLoadedWithNewValue(ThisReg, hp2) then
+                                RegInUse := False;
+                            end;
+
+                          if not RegInUse then
                             begin
                               DebugMsg(SPeepholeOptimization + 'Simplified register usage so ' + debug_regname(taicpu(hp1).oper[1]^.reg) + ' = ' + debug_regname(taicpu(p).oper[1]^.reg), p);
                               ThisReg := taicpu(hp1).oper[1]^.reg;