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;