While the default function returning 128-bit integer works correctly,
Random_Discrete does not if it is instantiated on a 128-bit integer,
since the magnitude of the returned numbers is still 64 bits.

Note that no counterpart is needed in GNAT.Random_Numbers because the
homonymous function in there is just a forwarder for the original one.

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

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.
diff --git a/gcc/ada/libgnat/s-rannum.adb b/gcc/ada/libgnat/s-rannum.adb
--- a/gcc/ada/libgnat/s-rannum.adb
+++ b/gcc/ada/libgnat/s-rannum.adb
@@ -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.
 


Reply via email to