[Ada] Adjust support for 128-bit integer types in System.Random_Numbers
authorEric Botcazou <ebotcazou@adacore.com>
Tue, 13 Oct 2020 07:15:23 +0000 (09:15 +0200)
committerPierre-Marie de Rodat <derodat@adacore.com>
Wed, 25 Nov 2020 13:22:28 +0000 (08:22 -0500)
gcc/ada/

* libgnat/s-rannum.adb (Random_Discrete): Specifically deal with
the case where the size of the base type is larger than 64 bits.

gcc/ada/libgnat/s-rannum.adb

index e65e6a7723344810a3d1cef569e3dac2e0678bca..ab6428f9ff8a8d83a3cb9920c514780e31b6d0c3 100644 (file)
@@ -409,6 +409,41 @@ is
       elsif Max < Min then
          raise Constraint_Error;
 
+      --  In the 128-bit case, we have to be careful since not all 128-bit
+      --  unsigned values are representable in GNAT's universal integer.
+
+      elsif Result_Subtype'Base'Size > 64 then
+         declare
+            --  Ignore unequal-size warnings since GNAT's handling is correct.
+
+            pragma Warnings ("Z");
+            function Conv_To_Unsigned is
+               new Unchecked_Conversion (Result_Subtype'Base, Unsigned_128);
+            function Conv_To_Result is
+               new Unchecked_Conversion (Unsigned_128, Result_Subtype'Base);
+            pragma Warnings ("z");
+
+            N : constant Unsigned_128 :=
+                  Conv_To_Unsigned (Max) - Conv_To_Unsigned (Min) + 1;
+
+            X, Slop : Unsigned_128;
+
+         begin
+            if N = 0 then
+               return Conv_To_Result (Conv_To_Unsigned (Min) + Random (Gen));
+
+            else
+               Slop := Unsigned_128'Last rem N + 1;
+
+               loop
+                  X := Random (Gen);
+                  exit when Slop = N or else X <= Unsigned_128'Last - Slop;
+               end loop;
+
+               return Conv_To_Result (Conv_To_Unsigned (Min) + X rem N);
+            end if;
+         end;
+
       --  In the 64-bit case, we have to be careful since not all 64-bit
       --  unsigned values are representable in GNAT's universal integer.