aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/libgnat/s-arit32.adb
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/libgnat/s-arit32.adb')
-rw-r--r--gcc/ada/libgnat/s-arit32.adb398
1 files changed, 4 insertions, 394 deletions
diff --git a/gcc/ada/libgnat/s-arit32.adb b/gcc/ada/libgnat/s-arit32.adb
index 91082e7..0cc88ed 100644
--- a/gcc/ada/libgnat/s-arit32.adb
+++ b/gcc/ada/libgnat/s-arit32.adb
@@ -34,20 +34,11 @@
-- would be too costly otherwise. This is enforced by setting the assertion
-- policy to Ignore.
-pragma Assertion_Policy (Pre => Ignore,
- Post => Ignore,
- Ghost => Ignore,
- Loop_Invariant => Ignore,
- Assert => Ignore);
-
-with Ada.Numerics.Big_Numbers.Big_Integers_Ghost;
-use Ada.Numerics.Big_Numbers.Big_Integers_Ghost;
with Ada.Unchecked_Conversion;
package body System.Arith_32
with SPARK_Mode
is
-
pragma Suppress (Overflow_Check);
pragma Suppress (Range_Check);
@@ -58,33 +49,6 @@ is
function To_Int is new Ada.Unchecked_Conversion (Uns32, Int32);
- package Unsigned_Conversion is new Unsigned_Conversions (Int => Uns32);
-
- function Big (Arg : Uns32) return Big_Integer is
- (Unsigned_Conversion.To_Big_Integer (Arg))
- with Ghost;
-
- package Unsigned_Conversion_64 is new Unsigned_Conversions (Int => Uns64);
-
- function Big (Arg : Uns64) return Big_Integer is
- (Unsigned_Conversion_64.To_Big_Integer (Arg))
- with Ghost;
-
- pragma Warnings
- (Off, "non-preelaborable call not allowed in preelaborated unit",
- Reason => "Ghost code is not compiled");
- Big_0 : constant Big_Integer :=
- Big (Uns32'(0))
- with Ghost;
- Big_2xx32 : constant Big_Integer :=
- Big (Uns32'(2 ** 32 - 1)) + 1
- with Ghost;
- Big_2xx64 : constant Big_Integer :=
- Big (Uns64'(2 ** 64 - 1)) + 1
- with Ghost;
- pragma Warnings
- (On, "non-preelaborable call not allowed in preelaborated unit");
-
-----------------------
-- Local Subprograms --
-----------------------
@@ -96,166 +60,23 @@ is
-- Convert absolute value of X to unsigned. Note that we can't just use
-- the expression of the Else since it overflows for X = Int32'First.
- function Lo (A : Uns64) return Uns32 is (Uns32 (A and (2 ** 32 - 1)));
- -- Low order half of 64-bit value
-
function Hi (A : Uns64) return Uns32 is (Uns32 (Shift_Right (A, 32)));
-- High order half of 64-bit value
- function To_Neg_Int (A : Uns32) return Int32
- with
- Pre => In_Int32_Range (-Big (A)),
- Post => Big (To_Neg_Int'Result) = -Big (A);
+ function To_Neg_Int (A : Uns32) return Int32;
-- Convert to negative integer equivalent. If the input is in the range
-- 0 .. 2**31, then the corresponding nonpositive signed integer (obtained
-- by negating the given value) is returned, otherwise constraint error is
-- raised.
- function To_Pos_Int (A : Uns32) return Int32
- with
- Pre => In_Int32_Range (Big (A)),
- Post => Big (To_Pos_Int'Result) = Big (A);
+ function To_Pos_Int (A : Uns32) return Int32;
-- Convert to positive integer equivalent. If the input is in the range
-- 0 .. 2**31 - 1, then the corresponding nonnegative signed integer is
-- returned, otherwise constraint error is raised.
- procedure Raise_Error with
- Always_Terminates,
- Exceptional_Cases => (Constraint_Error => True);
- pragma No_Return (Raise_Error);
+ procedure Raise_Error with No_Return;
-- Raise constraint error with appropriate message
- ------------------
- -- Local Lemmas --
- ------------------
-
- procedure Lemma_Abs_Commutation (X : Int32)
- with
- Ghost,
- Post => abs Big (X) = Big (Uns32'(abs X));
-
- procedure Lemma_Abs_Div_Commutation (X, Y : Big_Integer)
- with
- Ghost,
- Pre => Y /= 0,
- Post => abs (X / Y) = abs X / abs Y;
-
- procedure Lemma_Abs_Mult_Commutation (X, Y : Big_Integer)
- with
- Ghost,
- Post => abs (X * Y) = abs X * abs Y;
-
- procedure Lemma_Abs_Rem_Commutation (X, Y : Big_Integer)
- with
- Ghost,
- Pre => Y /= 0,
- Post => abs (X rem Y) = (abs X) rem (abs Y);
-
- procedure Lemma_Div_Commutation (X, Y : Uns64)
- with
- Ghost,
- Pre => Y /= 0,
- Post => Big (X) / Big (Y) = Big (X / Y);
-
- procedure Lemma_Div_Ge (X, Y, Z : Big_Integer)
- with
- Ghost,
- Pre => Z > 0 and then X >= Y * Z,
- Post => X / Z >= Y;
-
- procedure Lemma_Ge_Commutation (A, B : Uns32)
- with
- Ghost,
- Pre => A >= B,
- Post => Big (A) >= Big (B);
-
- procedure Lemma_Hi_Lo (Xu : Uns64; Xhi, Xlo : Uns32)
- with
- Ghost,
- Pre => Xhi = Hi (Xu) and Xlo = Lo (Xu),
- Post => Big (Xu) = Big_2xx32 * Big (Xhi) + Big (Xlo);
-
- procedure Lemma_Mult_Commutation (X, Y, Z : Uns64)
- with
- Ghost,
- Pre => Big (X) * Big (Y) < Big_2xx64 and then Z = X * Y,
- Post => Big (X) * Big (Y) = Big (Z);
-
- procedure Lemma_Mult_Non_Negative (X, Y : Big_Integer)
- with
- Ghost,
- Pre => (X >= Big_0 and then Y >= Big_0)
- or else (X <= Big_0 and then Y <= Big_0),
- Post => X * Y >= Big_0;
-
- procedure Lemma_Mult_Non_Positive (X, Y : Big_Integer)
- with
- Ghost,
- Pre => (X <= Big_0 and then Y >= Big_0)
- or else (X >= Big_0 and then Y <= Big_0),
- Post => X * Y <= Big_0;
-
- procedure Lemma_Neg_Rem (X, Y : Big_Integer)
- with
- Ghost,
- Pre => Y /= 0,
- Post => X rem Y = X rem (-Y);
-
- procedure Lemma_Not_In_Range_Big2xx32
- with
- Post => not In_Int32_Range (Big_2xx32)
- and then not In_Int32_Range (-Big_2xx32);
-
- procedure Lemma_Rem_Commutation (X, Y : Uns64)
- with
- Ghost,
- Pre => Y /= 0,
- Post => Big (X) rem Big (Y) = Big (X rem Y);
-
- -----------------------------
- -- Local lemma null bodies --
- -----------------------------
-
- procedure Lemma_Abs_Commutation (X : Int32) is null;
- procedure Lemma_Abs_Div_Commutation (X, Y : Big_Integer) is null;
- procedure Lemma_Abs_Mult_Commutation (X, Y : Big_Integer) is null;
- procedure Lemma_Div_Commutation (X, Y : Uns64) is null;
- procedure Lemma_Div_Ge (X, Y, Z : Big_Integer) is null;
- procedure Lemma_Ge_Commutation (A, B : Uns32) is null;
- procedure Lemma_Mult_Commutation (X, Y, Z : Uns64) is null;
- procedure Lemma_Mult_Non_Negative (X, Y : Big_Integer) is null;
- procedure Lemma_Mult_Non_Positive (X, Y : Big_Integer) is null;
- procedure Lemma_Neg_Rem (X, Y : Big_Integer) is null;
- procedure Lemma_Not_In_Range_Big2xx32 is null;
- procedure Lemma_Rem_Commutation (X, Y : Uns64) is null;
-
- -------------------------------
- -- Lemma_Abs_Rem_Commutation --
- -------------------------------
-
- procedure Lemma_Abs_Rem_Commutation (X, Y : Big_Integer) is
- begin
- if Y < 0 then
- Lemma_Neg_Rem (X, Y);
- if X < 0 then
- pragma Assert (X rem Y = -((-X) rem (-Y)));
- pragma Assert (abs (X rem Y) = (abs X) rem (abs Y));
- else
- pragma Assert (abs (X rem Y) = (abs X) rem (abs Y));
- end if;
- end if;
- end Lemma_Abs_Rem_Commutation;
-
- -----------------
- -- Lemma_Hi_Lo --
- -----------------
-
- procedure Lemma_Hi_Lo (Xu : Uns64; Xhi, Xlo : Uns32) is
- begin
- pragma Assert (Uns64 (Xhi) = Xu / Uns64'(2 ** 32));
- pragma Assert (Uns64 (Xlo) = Xu mod 2 ** 32);
- end Lemma_Hi_Lo;
-
-----------------
-- Raise_Error --
-----------------
@@ -263,9 +84,6 @@ is
procedure Raise_Error is
begin
raise Constraint_Error with "32-bit arithmetic overflow";
- pragma Annotate
- (GNATprove, Intentional, "exception might be raised",
- "Procedure Raise_Error is called to signal input errors");
end Raise_Error;
-------------------
@@ -288,197 +106,20 @@ is
Ru : Uns32;
-- Unsigned quotient and remainder
- -- Local ghost variables
-
- Mult : constant Big_Integer := abs (Big (X) * Big (Y)) with Ghost;
- Quot : Big_Integer with Ghost;
- Big_R : Big_Integer with Ghost;
- Big_Q : Big_Integer with Ghost;
-
- -- Local lemmas
-
- procedure Prove_Negative_Dividend
- with
- Ghost,
- Pre => Z /= 0
- and then ((X >= 0 and Y < 0) or (X < 0 and Y >= 0))
- and then Big_Q =
- (if Round then Round_Quotient (Big (X) * Big (Y), Big (Z),
- Big (X) * Big (Y) / Big (Z),
- Big (X) * Big (Y) rem Big (Z))
- else Big (X) * Big (Y) / Big (Z)),
- Post =>
- (if Z > 0 then Big_Q <= Big_0 else Big_Q >= Big_0);
- -- Proves the sign of rounded quotient when dividend is non-positive
-
- procedure Prove_Overflow
- with
- Ghost,
- Pre => Z /= 0 and then Mult >= Big_2xx32 * Big (Uns32'(abs Z)),
- Post => not In_Int32_Range (Big (X) * Big (Y) / Big (Z))
- and then not In_Int32_Range
- (Round_Quotient (Big (X) * Big (Y), Big (Z),
- Big (X) * Big (Y) / Big (Z),
- Big (X) * Big (Y) rem Big (Z)));
- -- Proves overflow case
-
- procedure Prove_Positive_Dividend
- with
- Ghost,
- Pre => Z /= 0
- and then ((X >= 0 and Y >= 0) or (X < 0 and Y < 0))
- and then Big_Q =
- (if Round then Round_Quotient (Big (X) * Big (Y), Big (Z),
- Big (X) * Big (Y) / Big (Z),
- Big (X) * Big (Y) rem Big (Z))
- else Big (X) * Big (Y) / Big (Z)),
- Post =>
- (if Z > 0 then Big_Q >= Big_0 else Big_Q <= Big_0);
- -- Proves the sign of rounded quotient when dividend is non-negative
-
- procedure Prove_Rounding_Case
- with
- Ghost,
- Pre => Z /= 0
- and then Quot = Big (X) * Big (Y) / Big (Z)
- and then Big_R = Big (X) * Big (Y) rem Big (Z)
- and then Big_Q =
- Round_Quotient (Big (X) * Big (Y), Big (Z), Quot, Big_R)
- and then Big (Ru) = abs Big_R
- and then Big (Zu) = Big (Uns32'(abs Z)),
- Post => abs Big_Q =
- (if Ru > (Zu - Uns32'(1)) / Uns32'(2)
- then abs Quot + 1
- else abs Quot);
- -- Proves correctness of the rounding of the unsigned quotient
-
- procedure Prove_Sign_R
- with
- Ghost,
- Pre => Z /= 0 and then Big_R = Big (X) * Big (Y) rem Big (Z),
- Post => In_Int32_Range (Big_R);
-
- procedure Prove_Signs
- with
- Ghost,
- Pre => Z /= 0
- and then Quot = Big (X) * Big (Y) / Big (Z)
- and then Big_R = Big (X) * Big (Y) rem Big (Z)
- and then Big_Q =
- (if Round then
- Round_Quotient (Big (X) * Big (Y), Big (Z), Quot, Big_R)
- else Quot)
- and then Big (Ru) = abs Big_R
- and then Big (Qu) = abs Big_Q
- and then In_Int32_Range (Big_Q)
- and then In_Int32_Range (Big_R)
- and then R =
- (if (X >= 0) = (Y >= 0) then To_Pos_Int (Ru) else To_Neg_Int (Ru))
- and then Q =
- (if ((X >= 0) = (Y >= 0)) = (Z >= 0) then To_Pos_Int (Qu)
- else To_Neg_Int (Qu)), -- need to ensure To_Pos_Int precondition
- Post => Big (R) = Big_R and then Big (Q) = Big_Q;
- -- Proves final signs match the intended result after the unsigned
- -- division is done.
-
- -----------------------------
- -- Prove_Negative_Dividend --
- -----------------------------
-
- procedure Prove_Negative_Dividend is
- begin
- Lemma_Mult_Non_Positive (Big (X), Big (Y));
- end Prove_Negative_Dividend;
-
- --------------------
- -- Prove_Overflow --
- --------------------
-
- procedure Prove_Overflow is
- begin
- Lemma_Div_Ge (Mult, Big_2xx32, Big (Uns32'(abs Z)));
- Lemma_Abs_Commutation (Z);
- Lemma_Abs_Div_Commutation (Big (X) * Big (Y), Big (Z));
- end Prove_Overflow;
-
- -----------------------------
- -- Prove_Positive_Dividend --
- -----------------------------
-
- procedure Prove_Positive_Dividend is
- begin
- Lemma_Mult_Non_Negative (Big (X), Big (Y));
- end Prove_Positive_Dividend;
-
- -------------------------
- -- Prove_Rounding_Case --
- -------------------------
-
- procedure Prove_Rounding_Case is
- begin
- if Same_Sign (Big (X) * Big (Y), Big (Z)) then
- pragma Assert
- (abs Big_Q =
- (if Ru > (Zu - Uns32'(1)) / Uns32'(2)
- then abs Quot + 1
- else abs Quot));
- end if;
- end Prove_Rounding_Case;
-
- ------------------
- -- Prove_Sign_R --
- ------------------
-
- procedure Prove_Sign_R is
- begin
- pragma Assert (In_Int32_Range (Big (Z)));
- end Prove_Sign_R;
-
- -----------------
- -- Prove_Signs --
- -----------------
-
- procedure Prove_Signs is
- begin
- if (X >= 0) = (Y >= 0) then
- pragma Assert (Big (R) = Big_R and then Big (Q) = Big_Q);
- else
- pragma Assert (Big (R) = Big_R and then Big (Q) = Big_Q);
- end if;
- end Prove_Signs;
-
- -- Start of processing for Scaled_Divide32
-
begin
-- First do the 64-bit multiplication
D := Uns64 (Xu) * Uns64 (Yu);
- Lemma_Abs_Mult_Commutation (Big (X), Big (Y));
- pragma Assert (Mult = Big (D));
- Lemma_Hi_Lo (D, Hi (D), Lo (D));
- pragma Assert (Mult = Big_2xx32 * Big (Hi (D)) + Big (Lo (D)));
-
-- If divisor is zero, raise error
if Z = 0 then
Raise_Error;
end if;
- Quot := Big (X) * Big (Y) / Big (Z);
- Big_R := Big (X) * Big (Y) rem Big (Z);
- if Round then
- Big_Q := Round_Quotient (Big (X) * Big (Y), Big (Z), Quot, Big_R);
- else
- Big_Q := Quot;
- end if;
-
-- If dividend is too large, raise error
if Hi (D) >= Zu then
- Lemma_Ge_Commutation (Hi (D), Zu);
- pragma Assert (Mult >= Big_2xx32 * Big (Zu));
- Prove_Overflow;
Raise_Error;
end if;
@@ -487,35 +128,14 @@ is
Qu := Uns32 (D / Uns64 (Zu));
Ru := Uns32 (D rem Uns64 (Zu));
- Lemma_Abs_Div_Commutation (Big (X) * Big (Y), Big (Z));
- Lemma_Abs_Rem_Commutation (Big (X) * Big (Y), Big (Z));
- Lemma_Abs_Commutation (X);
- Lemma_Abs_Commutation (Y);
- Lemma_Abs_Commutation (Z);
- Lemma_Mult_Commutation (Uns64 (Xu), Uns64 (Yu), D);
- Lemma_Div_Commutation (D, Uns64 (Zu));
- Lemma_Rem_Commutation (D, Uns64 (Zu));
-
- pragma Assert (Uns64 (Qu) = D / Uns64 (Zu));
- pragma Assert (Uns64 (Ru) = D rem Uns64 (Zu));
- pragma Assert (Big (Ru) = abs Big_R);
- pragma Assert (Big (Qu) = abs Quot);
- pragma Assert (Big (Zu) = Big (Uns32'(abs Z)));
-
-- Deal with rounding case
if Round then
- Prove_Rounding_Case;
-
if Ru > (Zu - Uns32'(1)) / Uns32'(2) then
- pragma Assert (abs Big_Q = Big (Qu) + 1);
-
-- Protect against wrapping around when rounding, by signaling
-- an overflow when the quotient is too large.
if Qu = Uns32'Last then
- pragma Assert (abs Big_Q = Big_2xx32);
- Lemma_Not_In_Range_Big2xx32;
Raise_Error;
end if;
@@ -523,31 +143,20 @@ is
end if;
end if;
- pragma Assert (In_Int32_Range (Big_Q));
- pragma Assert (Big (Qu) = abs Big_Q);
- pragma Assert (Big (Ru) = abs Big_R);
- Prove_Sign_R;
-
-- Set final signs (RM 4.5.5(27-30))
-- Case of dividend (X * Y) sign positive
if (X >= 0 and then Y >= 0) or else (X < 0 and then Y < 0) then
- Prove_Positive_Dividend;
-
R := To_Pos_Int (Ru);
Q := (if Z > 0 then To_Pos_Int (Qu) else To_Neg_Int (Qu));
-- Case of dividend (X * Y) sign negative
else
- Prove_Negative_Dividend;
-
R := To_Neg_Int (Ru);
Q := (if Z > 0 then To_Neg_Int (Qu) else To_Pos_Int (Qu));
end if;
-
- Prove_Signs;
end Scaled_Divide32;
----------------
@@ -559,6 +168,7 @@ is
(if A = 2**31 then Int32'First else -To_Int (A));
-- Note that we can't just use the expression of the Else, because it
-- overflows for A = 2**31.
+
begin
if R <= 0 then
return R;