Commit ec2dd67a by Robert Dewar Committed by Arnaud Charlet

checks.adb (Apply_Arithmetic_Overflow_Check): Avoid intermediate overflow if…

checks.adb (Apply_Arithmetic_Overflow_Check): Avoid intermediate overflow if result converted to wider integer type.

2008-05-20  Robert Dewar  <dewar@adacore.com>
	    Gary Dismukes  <dismukes@adacore.com>

	* checks.adb (Apply_Arithmetic_Overflow_Check): Avoid intermediate
	overflow if result converted to wider integer type.
	(Apply_Type_Conversion_Checks): Don't emit checks on conversions to
	discriminated types when discriminant checks are suppressed.

From-SVN: r135616
parent 57f56c63
...@@ -765,17 +765,120 @@ package body Checks is ...@@ -765,17 +765,120 @@ package body Checks is
-- Apply_Arithmetic_Overflow_Check -- -- Apply_Arithmetic_Overflow_Check --
------------------------------------- -------------------------------------
-- This routine is called only if the type is an integer type, and -- This routine is called only if the type is an integer type, and a
-- a software arithmetic overflow check must be performed for op -- software arithmetic overflow check may be needed for op (add, subtract,
-- (add, subtract, multiply). The check is performed only if -- or multiply). This check is performed only if Software_Overflow_Checking
-- Software_Overflow_Checking is enabled and Do_Overflow_Check -- is enabled and Do_Overflow_Check is set. In this case we expand the
-- is set. In this case we expand the operation into a more complex -- operation into a more complex sequence of tests that ensures that
-- sequence of tests that ensures that overflow is properly caught. -- overflow is properly caught.
procedure Apply_Arithmetic_Overflow_Check (N : Node_Id) is procedure Apply_Arithmetic_Overflow_Check (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N); Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N); Typ : Entity_Id := Etype (N);
Rtyp : constant Entity_Id := Root_Type (Typ); Rtyp : Entity_Id := Root_Type (Typ);
begin
-- An interesting special case. If the arithmetic operation appears as
-- the operand of a type conversion:
-- type1 (x op y)
-- and all the following conditions apply:
-- arithmetic operation is for a signed integer type
-- target type type1 is a static integer subtype
-- range of x and y are both included in the range of type1
-- range of x op y is included in the range of type1
-- size of type1 is at least twice the result size of op
-- then we don't do an overflow check in any case, instead we transform
-- the operation so that we end up with:
-- type1 (type1 (x) op type1 (y))
-- This avoids intermediate overflow before the conversion. It is
-- explicitly permitted by RM 3.5.4(24):
-- For the execution of a predefined operation of a signed integer
-- type, the implementation need not raise Constraint_Error if the
-- result is outside the base range of the type, so long as the
-- correct result is produced.
-- It's hard to imagine that any programmer counts on the exception
-- being raised in this case, and in any case it's wrong coding to
-- have this expectation, given the RM permission. Furthermore, other
-- Ada compilers do allow such out of range results.
-- Note that we do this transformation even if overflow checking is
-- off, since this is precisely about giving the "right" result and
-- avoiding the need for an overflow check.
if Is_Signed_Integer_Type (Typ)
and then Nkind (Parent (N)) = N_Type_Conversion
then
declare
Target_Type : constant Entity_Id :=
Base_Type (Entity (Subtype_Mark (Parent (N))));
Llo, Lhi : Uint;
Rlo, Rhi : Uint;
LOK, ROK : Boolean;
Vlo : Uint;
Vhi : Uint;
VOK : Boolean;
Tlo : Uint;
Thi : Uint;
begin
if Is_Integer_Type (Target_Type)
and then RM_Size (Root_Type (Target_Type)) >= 2 * RM_Size (Rtyp)
then
Tlo := Expr_Value (Type_Low_Bound (Target_Type));
Thi := Expr_Value (Type_High_Bound (Target_Type));
Determine_Range (Left_Opnd (N), LOK, Llo, Lhi);
Determine_Range (Right_Opnd (N), ROK, Rlo, Rhi);
if (LOK and ROK)
and then Tlo <= Llo and then Lhi <= Thi
and then Tlo <= Rlo and then Rhi <= Thi
then
Determine_Range (N, VOK, Vlo, Vhi);
if VOK and then Tlo <= Vlo and then Vhi <= Thi then
Rewrite (Left_Opnd (N),
Make_Type_Conversion (Loc,
Subtype_Mark => New_Occurrence_Of (Target_Type, Loc),
Expression => Relocate_Node (Left_Opnd (N))));
Rewrite (Right_Opnd (N),
Make_Type_Conversion (Loc,
Subtype_Mark => New_Occurrence_Of (Target_Type, Loc),
Expression => Relocate_Node (Right_Opnd (N))));
Set_Etype (N, Target_Type);
Typ := Target_Type;
Rtyp := Root_Type (Typ);
Analyze_And_Resolve (Left_Opnd (N), Target_Type);
Analyze_And_Resolve (Right_Opnd (N), Target_Type);
-- Given that the target type is twice the size of the
-- source type, overflow is now impossible, so we can
-- safely kill the overflow check and return.
Set_Do_Overflow_Check (N, False);
return;
end if;
end if;
end if;
end;
end if;
-- Now see if an overflow check is required
declare
Siz : constant Int := UI_To_Int (Esize (Rtyp)); Siz : constant Int := UI_To_Int (Esize (Rtyp));
Dsiz : constant Int := Siz * 2; Dsiz : constant Int := Siz * 2;
Opnod : Node_Id; Opnod : Node_Id;
...@@ -784,20 +887,22 @@ package body Checks is ...@@ -784,20 +887,22 @@ package body Checks is
Cent : RE_Id; Cent : RE_Id;
begin begin
-- Skip this if overflow checks are done in back end, or the overflow -- Skip check if back end does overflow checks, or the overflow flag
-- flag is not set anyway, or we are not doing code expansion. -- is not set anyway, or we are not doing code expansion.
-- Special case CLI target, where arithmetic overflow checks can be -- Special case CLI target, where arithmetic overflow checks can be
-- performed for integer and long_integer -- performed for integer and long_integer
if Backend_Overflow_Checks_On_Target if Backend_Overflow_Checks_On_Target
or else (VM_Target = CLI_Target and then Siz >= Standard_Integer_Size)
or else not Do_Overflow_Check (N) or else not Do_Overflow_Check (N)
or else not Expander_Active or else not Expander_Active
or else
(VM_Target = CLI_Target and then Siz >= Standard_Integer_Size)
then then
return; return;
end if; end if;
-- Otherwise, we generate the full general code for front end overflow -- Otherwise, generate the full general code for front end overflow
-- detection, which works by doing arithmetic in a larger type: -- detection, which works by doing arithmetic in a larger type:
-- x op y -- x op y
...@@ -810,7 +915,7 @@ package body Checks is ...@@ -810,7 +915,7 @@ package body Checks is
-- an integer type of sufficient length to hold the largest possible -- an integer type of sufficient length to hold the largest possible
-- result. -- result.
-- In the case where check type exceeds the size of Long_Long_Integer, -- If the size of check type exceeds the size of Long_Long_Integer,
-- we use a different approach, expanding to: -- we use a different approach, expanding to:
-- typ (xxx_With_Ovflo_Check (Integer_64 (x), Integer (y))) -- typ (xxx_With_Ovflo_Check (Integer_64 (x), Integer (y)))
...@@ -851,9 +956,9 @@ package body Checks is ...@@ -851,9 +956,9 @@ package body Checks is
return; return;
end if; end if;
-- If we fall through, we have the case where we do the arithmetic in -- If we fall through, we have the case where we do the arithmetic
-- the next higher type and get the check by conversion. In these cases -- in the next higher type and get the check by conversion. In these
-- Ctyp is set to the type to be used as the check type. -- cases Ctyp is set to the type to be used as the check type.
Opnod := Relocate_Node (N); Opnod := Relocate_Node (N);
...@@ -871,10 +976,11 @@ package body Checks is ...@@ -871,10 +976,11 @@ package body Checks is
Set_Analyzed (Opnd, True); Set_Analyzed (Opnd, True);
Set_Right_Opnd (Opnod, Opnd); Set_Right_Opnd (Opnod, Opnd);
-- The type of the operation changes to the base type of the check type, -- The type of the operation changes to the base type of the check
-- and we reset the overflow check indication, since clearly no overflow -- type, and we reset the overflow check indication, since clearly no
-- is possible now that we are using a double length type. We also set -- overflow is possible now that we are using a double length type.
-- the Analyzed flag to avoid a recursive attempt to expand the node. -- We also set the Analyzed flag to avoid a recursive attempt to
-- expand the node.
Set_Etype (Opnod, Base_Type (Ctyp)); Set_Etype (Opnod, Base_Type (Ctyp));
Set_Do_Overflow_Check (Opnod, False); Set_Do_Overflow_Check (Opnod, False);
...@@ -886,13 +992,14 @@ package body Checks is ...@@ -886,13 +992,14 @@ package body Checks is
Analyze (Opnd); Analyze (Opnd);
Set_Etype (Opnd, Typ); Set_Etype (Opnd, Typ);
-- In the discrete type case, we directly generate the range check for -- In the discrete type case, we directly generate the range check
-- the outer operand. This range check will implement the required -- for the outer operand. This range check will implement the
-- overflow check. -- required overflow check.
if Is_Discrete_Type (Typ) then if Is_Discrete_Type (Typ) then
Rewrite (N, Opnd); Rewrite (N, Opnd);
Generate_Range_Check (Expression (N), Typ, CE_Overflow_Check_Failed); Generate_Range_Check
(Expression (N), Typ, CE_Overflow_Check_Failed);
-- For other types, we enable overflow checking on the conversion, -- For other types, we enable overflow checking on the conversion,
-- after setting the node as analyzed to prevent recursive attempts -- after setting the node as analyzed to prevent recursive attempts
...@@ -907,6 +1014,7 @@ package body Checks is ...@@ -907,6 +1014,7 @@ package body Checks is
exception exception
when RE_Not_Available => when RE_Not_Available =>
return; return;
end;
end Apply_Arithmetic_Overflow_Check; end Apply_Arithmetic_Overflow_Check;
---------------------------- ----------------------------
...@@ -2231,6 +2339,7 @@ package body Checks is ...@@ -2231,6 +2339,7 @@ package body Checks is
end; end;
elsif Comes_From_Source (N) elsif Comes_From_Source (N)
and then not Discriminant_Checks_Suppressed (Target_Type)
and then Is_Record_Type (Target_Type) and then Is_Record_Type (Target_Type)
and then Is_Derived_Type (Target_Type) and then Is_Derived_Type (Target_Type)
and then not Is_Tagged_Type (Target_Type) and then not Is_Tagged_Type (Target_Type)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment