The Do_Overflow_Check flag was being set on division operators in
many cases where it was not needed. Now the flag will be set only
if there is a possibility of the (largest neg number) / (-1) case
and this only if code is not being generated (-gnatc mode), since
if code is generated, the check is explicitly generated. The test
program:

     1. procedure JunkDCheck
     2.   (Y : Positive;
     3.    X, Z : in out Integer) is
     4. begin
     5.    Z := X / Z;
     6.    X := 10 / Y;
     7. end;

if compiled with -gnatc -gnatG generates:

procedure junkdcheck
 (y : positive; x : in out integer;
  z : in out integer) is
begin
   z := x {/} z;
   x := 10 / y;
end junkdcheck;

(previously the second assignment had {/}

and if compiled with -gnatc -gnatG:

procedure junkdcheck
 (y : positive; x : in out integer;
  z : in out integer) is
begin
   [constraint_error when
     z = 0
     "divide by zero"]
   [constraint_error when
     x = -16#8000_0000# and then z = -1
     "overflow check failed"]
   z := x / z;
   x := 10 / y;
   return;
end junkdcheck;

Tested on x86_64-pc-linux-gnu, committed on trunk

2014-07-31  Robert Dewar  <de...@adacore.com>

        * checks.adb (Enable_Overflow_Check): More precise setting of
        Do_Overflow_Check flag for division.

Index: checks.adb
===================================================================
--- checks.adb  (revision 213325)
+++ checks.adb  (working copy)
@@ -1795,6 +1795,8 @@
          if Do_Overflow_Check (N)
            and then not Overflow_Checks_Suppressed (Etype (N))
          then
+            Set_Do_Overflow_Check (N, False);
+
             --  Test for extremely annoying case of xxx'First divided by -1
             --  for division of signed integer types (only overflow case).
 
@@ -1855,6 +1857,8 @@
          --  it is a Division_Check and not an Overflow_Check.
 
          if Do_Division_Check (N) then
+            Set_Do_Division_Check (N, False);
+
             if (not ROK) or else (Rlo <= 0 and then 0 <= Rhi) then
                Insert_Action (N,
                  Make_Raise_Constraint_Error (Loc,
@@ -5110,6 +5114,8 @@
       Lo   : Uint;
       Hi   : Uint;
 
+      Do_Ovflow_Check : Boolean;
+
    begin
       if Debug_Flag_CC then
          w ("Enable_Overflow_Check for node ", Int (N));
@@ -5187,15 +5193,52 @@
          --   c) The alternative is a lot of special casing in this routine
          --      which would partially duplicate Determine_Range processing.
 
-         if OK
-           and then Lo > Expr_Value (Type_Low_Bound  (Typ))
-           and then Hi < Expr_Value (Type_High_Bound (Typ))
-         then
-            if Debug_Flag_CC then
-               w ("No overflow check required");
+         if OK then
+            Do_Ovflow_Check := True;
+
+            --  Note that the following checks are quite deliberately > and <
+            --  rather than >= and <= as explained above.
+
+            if  Lo > Expr_Value (Type_Low_Bound  (Typ))
+                  and then
+                Hi < Expr_Value (Type_High_Bound (Typ))
+            then
+               Do_Ovflow_Check := False;
+
+            --  Despite the comments above, it is worth dealing specially with
+            --  division specially. The only case where integer division can
+            --  overflow is (largest negative number) / (-1). So we will do
+            --  an extra range analysis to see if this is possible.
+
+            elsif Nkind (N) = N_Op_Divide then
+               Determine_Range
+                 (Left_Opnd (N), OK, Lo, Hi, Assume_Valid => True);
+
+               if OK and then Lo > Expr_Value (Type_Low_Bound (Typ)) then
+                  Do_Ovflow_Check := False;
+
+               else
+                  Determine_Range
+                    (Right_Opnd (N), OK, Lo, Hi, Assume_Valid => True);
+
+                  if OK and then (Lo > Uint_Minus_1
+                                    or else
+                                  Hi < Uint_Minus_1)
+                  then
+                     Do_Ovflow_Check := False;
+                  end if;
+               end if;
             end if;
 
-            return;
+            --  If no overflow check required, we are done
+
+            if not Do_Ovflow_Check then
+               if Debug_Flag_CC then
+                  w ("No overflow check required");
+               end if;
+
+               return;
+            end if;
          end if;
       end if;
 

Reply via email to