2
0
Эх сурвалжийг харах

Overflow bug fixes to MovZX/SX optimisations when CMP instructions are encountered.

J. Gareth "Curious Kit" Moreton 3 жил өмнө
parent
commit
b4c8c1da12

+ 83 - 53
compiler/x86/aoptx86.pas

@@ -7968,7 +7968,7 @@ unit aoptx86;
         function CheckOverflowConditions: Boolean;
         function CheckOverflowConditions: Boolean;
           begin
           begin
             Result := True;
             Result := True;
-            if (TestValSignedMax > SignedUpperLimit) or (TestValSignedMax < SignedUpperLimitBottom) then
+            if (TestValSignedMax > SignedUpperLimit) then
               UpperSignedOverflow := True;
               UpperSignedOverflow := True;
 
 
             if (TestValSignedMax > SignedLowerLimit) or (TestValSignedMax < SignedLowerLimitBottom) then
             if (TestValSignedMax > SignedLowerLimit) or (TestValSignedMax < SignedLowerLimitBottom) then
@@ -7978,7 +7978,7 @@ unit aoptx86;
               LowerUnsignedOverflow := True;
               LowerUnsignedOverflow := True;
 
 
             if (TestValMin > UpperLimit) or (TestValMax > UpperLimit) or (TestValSignedMax > UpperLimit) or
             if (TestValMin > UpperLimit) or (TestValMax > UpperLimit) or (TestValSignedMax > UpperLimit) or
-              (TestValMin < SignedUpperLimitBottom) or (TestValMax < SignedUpperLimitBottom) or (TestValSignedMax > SignedUpperLimit) then
+              (TestValMin < SignedUpperLimitBottom) or (TestValMax < SignedUpperLimitBottom) or (TestValSignedMax < SignedUpperLimitBottom) then
               begin
               begin
                 { Absolute overflow }
                 { Absolute overflow }
                 Result := False;
                 Result := False;
@@ -8270,12 +8270,15 @@ unit aoptx86;
                       smallest allowed signed value for the minimum size (e.g.
                       smallest allowed signed value for the minimum size (e.g.
                       -128 for 8-bit) }
                       -128 for 8-bit) }
                     not (
                     not (
-                      ((taicpu(hp1).oper[0]^.val and UpperLimit) = taicpu(hp1).oper[0]^.val) or
+                      ((taicpu(hp1).oper[0]^.val and LowerLimit) = taicpu(hp1).oper[0]^.val) or
                       { Is it in the negative range? }
                       { Is it in the negative range? }
-                      (taicpu(hp1).oper[0]^.val >= SignedLowerLimitBottom)
+                      (
+                        (taicpu(hp1).oper[0]^.val < 0) and
+                        (taicpu(hp1).oper[0]^.val >= SignedLowerLimitBottom)
+                      )
                     ) then
                     ) then
                     Break;
                     Break;
-
+(*
                   { ANDing can't increase the value past the limit or decrease
                   { ANDing can't increase the value past the limit or decrease
                     it below 0, so we can skip the checks, plus the test value
                     it below 0, so we can skip the checks, plus the test value
                     won't change afterwards }
                     won't change afterwards }
@@ -8285,17 +8288,6 @@ unit aoptx86;
                     (taicpu(hp1).oper[0]^.val <> 0) then
                     (taicpu(hp1).oper[0]^.val <> 0) then
                     begin
                     begin
                       WorkingValue := taicpu(hp1).oper[0]^.val;
                       WorkingValue := taicpu(hp1).oper[0]^.val;
-                      case MinSize of
-                        S_B:
-                          if (WorkingValue and $ff)<>WorkingValue then
-                            break;
-                        S_W:
-                          if (WorkingValue and $ffff)<>WorkingValue then
-                            break;
-                        else
-                          ;
-                      end;
-
 
 
                       TestValMin := TestValMin - WorkingValue;
                       TestValMin := TestValMin - WorkingValue;
                       TestValMax := TestValMax - WorkingValue;
                       TestValMax := TestValMax - WorkingValue;
@@ -8309,18 +8301,36 @@ unit aoptx86;
                       TestValMin := TestValMin + WorkingValue;
                       TestValMin := TestValMin + WorkingValue;
                       TestValMax := TestValMax + WorkingValue;
                       TestValMax := TestValMax + WorkingValue;
                       TestValSignedMax := TestValSignedMax + WorkingValue;
                       TestValSignedMax := TestValSignedMax + WorkingValue;
-                    end;
+                    end; *)
 
 
                   { Check to see if the active register is used afterwards }
                   { Check to see if the active register is used afterwards }
                   TransferUsedRegs(TmpUsedRegs);
                   TransferUsedRegs(TmpUsedRegs);
                   IncludeRegInUsedRegs(ThisReg, TmpUsedRegs);
                   IncludeRegInUsedRegs(ThisReg, TmpUsedRegs);
                   if not RegUsedAfterInstruction(ThisReg, hp1, TmpUsedRegs) then
                   if not RegUsedAfterInstruction(ThisReg, hp1, TmpUsedRegs) then
                     begin
                     begin
-                      case MinSize of
+                      { Make sure the comparison or any previous instructions
+                        hasn't pushed the test values outside of the range of
+                        MinSize }
+                      if LowerUnsignedOverflow and not UpperUnsignedOverflow then
+                        begin
+                          { Exceeded lower bound but not upper bound }
+                          TargetSize := MaxSize;
+                        end
+                      else if not LowerSignedOverflow or not LowerUnsignedOverflow then
+                        begin
+                          { Size didn't exceed lower bound }
+                          TargetSize := MinSize;
+                        end
+                      else
+                        Break;
+
+                      case TargetSize of
                         S_B:
                         S_B:
                           TargetSubReg := R_SUBL;
                           TargetSubReg := R_SUBL;
                         S_W:
                         S_W:
                           TargetSubReg := R_SUBW;
                           TargetSubReg := R_SUBW;
+                        S_L:
+                          TargetSubReg := R_SUBD;
                         else
                         else
                           InternalError(2021051002);
                           InternalError(2021051002);
                       end;
                       end;
@@ -8427,19 +8437,14 @@ unit aoptx86;
                           end
                           end
                         else
                         else
                           begin
                           begin
-                            TestValMin := TestValMin + taicpu(hp1).oper[0]^.val;
-                            TestValMax := TestValMax + taicpu(hp1).oper[0]^.val;
-                            TestValSignedMax := TestValSignedMax + taicpu(hp1).oper[0]^.val;
+                            WorkingValue := taicpu(hp1).oper[0]^.val;
+                            TestValMin := TestValMin + WorkingValue;
+                            TestValMax := TestValMax + WorkingValue;
+                            TestValSignedMax := TestValSignedMax + WorkingValue;
                           end;
                           end;
                       end;
                       end;
                     A_SUB:
                     A_SUB:
                       begin
                       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
                         if (taicpu(hp1).oper[0]^.typ = top_reg) then
                           begin
                           begin
                             TestValMin := 0;
                             TestValMin := 0;
@@ -8448,9 +8453,16 @@ unit aoptx86;
                           end
                           end
                         else
                         else
                           begin
                           begin
-                            TestValMin := TestValMin - taicpu(hp1).oper[0]^.val;
-                            TestValMax := TestValMax - taicpu(hp1).oper[0]^.val;
-                            TestValSignedMax := TestValSignedMax - taicpu(hp1).oper[0]^.val;
+                            if OrXorUsed then
+                              { Too high a risk of non-linear behaviour that breaks DFA here }
+                              Break
+                            else
+                              BitwiseOnly := False;
+
+                            WorkingValue := taicpu(hp1).oper[0]^.val;
+                            TestValMin := TestValMin - WorkingValue;
+                            TestValMax := TestValMax - WorkingValue;
+                            TestValSignedMax := TestValSignedMax - WorkingValue;
                           end;
                           end;
                       end;
                       end;
                     A_AND:
                     A_AND:
@@ -8485,9 +8497,10 @@ unit aoptx86;
                                 InternalError(2020112320);
                                 InternalError(2020112320);
                             end;
                             end;
 
 
-                          TestValMin := TestValMin and taicpu(hp1).oper[0]^.val;
-                          TestValMax := TestValMax and taicpu(hp1).oper[0]^.val;
-                          TestValSignedMax := TestValSignedMax and taicpu(hp1).oper[0]^.val;
+                          WorkingValue := taicpu(hp1).oper[0]^.val;
+                          TestValMin := TestValMin and WorkingValue;
+                          TestValMax := TestValMax and WorkingValue;
+                          TestValSignedMax := TestValSignedMax and WorkingValue;
                         end;
                         end;
                     A_OR:
                     A_OR:
                       begin
                       begin
@@ -8496,33 +8509,49 @@ unit aoptx86;
 
 
                         OrXorUsed := True;
                         OrXorUsed := True;
 
 
-                        TestValMin := TestValMin or taicpu(hp1).oper[0]^.val;
-                        TestValMax := TestValMax or taicpu(hp1).oper[0]^.val;
-                        TestValSignedMax := TestValSignedMax or taicpu(hp1).oper[0]^.val;
+                        WorkingValue := taicpu(hp1).oper[0]^.val;
+                        TestValMin := TestValMin or WorkingValue;
+                        TestValMax := TestValMax or WorkingValue;
+                        TestValSignedMax := TestValSignedMax or WorkingValue;
                       end;
                       end;
                     A_XOR:
                     A_XOR:
                       begin
                       begin
-                        if not BitwiseOnly then
-                          Break;
+                        if (taicpu(hp1).oper[0]^.typ = top_reg) then
+                          begin
+                            TestValMin := 0;
+                            TestValMax := 0;
+                            TestValSignedMax := 0;
+                          end
+                        else
+                          begin
+                            if not BitwiseOnly then
+                              Break;
 
 
-                        OrXorUsed := True;
+                            OrXorUsed := True;
 
 
-                        TestValMin := TestValMin xor taicpu(hp1).oper[0]^.val;
-                        TestValMax := TestValMax xor taicpu(hp1).oper[0]^.val;
-                        TestValSignedMax := TestValSignedMax xor taicpu(hp1).oper[0]^.val;
+                            WorkingValue := taicpu(hp1).oper[0]^.val;
+                            TestValMin := TestValMin xor WorkingValue;
+                            TestValMax := TestValMax xor WorkingValue;
+                            TestValSignedMax := TestValSignedMax xor WorkingValue;
+                          end;
                       end;
                       end;
                     A_SHL:
                     A_SHL:
                       begin
                       begin
-                        TestValMin := TestValMin shl taicpu(hp1).oper[0]^.val;
-                        TestValMax := TestValMax shl taicpu(hp1).oper[0]^.val;
-                        TestValSignedMax := TestValSignedMax shl taicpu(hp1).oper[0]^.val;
+                        BitwiseOnly := False;
+
+                        WorkingValue := taicpu(hp1).oper[0]^.val;
+                        TestValMin := TestValMin shl WorkingValue;
+                        TestValMax := TestValMax shl WorkingValue;
+                        TestValSignedMax := TestValSignedMax shl WorkingValue;
                       end;
                       end;
                     A_SHR,
                     A_SHR,
                     { The first instruction was MOVZX, so the value won't be negative }
                     { The first instruction was MOVZX, so the value won't be negative }
                     A_SAR:
                     A_SAR:
                       begin
                       begin
-                        { we might be able to go smaller if SHR appears first }
-                        if InstrMax = -1 then
+                        if InstrMax <> -1 then
+                          BitwiseOnly := False
+                        else
+                          { we might be able to go smaller if SHR appears first }
                           case MinSize of
                           case MinSize of
                             S_B:
                             S_B:
                               ;
                               ;
@@ -8553,17 +8582,18 @@ unit aoptx86;
                               InternalError(2020112321);
                               InternalError(2020112321);
                           end;
                           end;
 
 
+                        WorkingValue := taicpu(hp1).oper[0]^.val;
                         if taicpu(hp1).opcode = A_SAR then
                         if taicpu(hp1).opcode = A_SAR then
                           begin
                           begin
-                            TestValMin := SarInt64(TestValMin, taicpu(hp1).oper[0]^.val);
-                            TestValMax := SarInt64(TestValMax, taicpu(hp1).oper[0]^.val);
-                            TestValSignedMax := SarInt64(TestValSignedMax, taicpu(hp1).oper[0]^.val);
+                            TestValMin := SarInt64(TestValMin, WorkingValue);
+                            TestValMax := SarInt64(TestValMax, WorkingValue);
+                            TestValSignedMax := SarInt64(TestValSignedMax, WorkingValue);
                           end
                           end
                         else
                         else
                           begin
                           begin
-                            TestValMin := TestValMin shr taicpu(hp1).oper[0]^.val;
-                            TestValMax := TestValMax shr taicpu(hp1).oper[0]^.val;
-                            TestValSignedMax := TestValSignedMax shr taicpu(hp1).oper[0]^.val;
+                            TestValMin := TestValMin shr WorkingValue;
+                            TestValMax := TestValMax shr WorkingValue;
+                            TestValSignedMax := TestValSignedMax shr WorkingValue;
                           end;
                           end;
                       end;
                       end;
                     else
                     else