4

Compilation fails with the F6 declaration below :

type F3 is delta 2.0**(-4) range 0.0 .. ((2.0**8)-1.0)*2.0**(-4);    -- byte  16#f.f#;
for f3'size use 8;

type F4 is delta 2.0**(-8) range 0.0 .. ((2.0**16)-1.0)*2.0**(-8);   -- word 16#ff.ff#
for f4'size use 16;

type F5 is delta 2.0**(-16) range 0.0 .. ((2.0**32)-1.0)*2.0**(-16); -- dword 16#ffff.ffff#
for f5'size use 32;

type F6 is delta 2.0**(-32) range 0.0 .. ((2.0**64)-1.0)*2.0**(-32); -- ldword 16#ffff_ffff.ffff_ffff#
for f6'size use 32;

Same failure both on linux64/v8.0.3 and on learn.adacore.com.

edit error message is "size required (65) for type "f6" too large, maximum allowed is 64"

edit add 'size instructions / intended upper bound in hex

edit added fixed type freeze trace below

loval -16#0.FF#E1, hival 16#0.FF#E1, Actual_Size  9
loval 0.0, hival 16#0.FF#E1, Actual_Size  8

loval -16#0.FFFF#E2, hival 16#0.FFFF#E2, Actual_Size  17
loval 0.0, hival 16#0.FFFF#E2, Actual_Size  16

loval -16#0.FFFF_FFFF#E4, hival 16#0.FFFF_FFFF#E4, Actual_Size  33
loval 0.0, hival 16#0.FFFF_FFFF#E4, Actual_Size  32

loval -16#0.FFFF_FFFF_FFFF_FFFF#E8, hival 16#0.FFFF_FFFF_FFFF_FFFF#E8, Actual_Size  64
loval 0.0, hival 16#0.FFFF_FFFF_FFFF_FFFF#E8, Actual_Size  63

2 Answers2

7

The base problem is that your GNAT does not support fixed point types with a size more than 64 bits, as the error message states. And F6 seems to require 65 bits. This happens because for fixed point types, the reference manual states:

The base range (see 3.5) of a fixed point type is symmetric around zero, except possibly for an extra negative value in some implementations.

This means that the base range of type F6 also includes the symmetric negative numbers and thus requires a sign bit. This is why, the representation of the base range needs 65 bits instead of 64 bits as you'd expect.

Now the manual also states that

An ordinary_fixed_point_definition also defines a constrained first subtype of the type

So F6 is a subtype of the base type requiring 65 bits. Due to the range constraints of F6, it would only need 64 bits of representation. As F6 is the first subtype, we may constrain its size with an attribute definition clause:

for F6'Size use 64;

This forces the compiler to try and use only 64 bits for representation. I am unsure whether this solves your problem; it could be that you cannot circumvent the error this way since the compiler requires a representible base type.

flyx
  • 35,506
  • 7
  • 89
  • 126
2

In addition to the answer of @flyx, you can see this by invoking GNAT with the -gnatdg switch. The type Tf6B (shown in the compiler output between brackets) is the actual underlying type for (sub)type f6. Type Tf6B is (almost) symmetric around 0, as @flyx already explained based on the Ada RM, and determined to have a size of 65 bits.

main.adb

procedure Main is

   type F6 is delta 2.0**(-32) range 0.0 .. ((2.0**64)-1.0)*2.0**(-32);
   for F6'Size use 64;

   X : F6;
   Y : F6'Base;     --  This should be possible.   

begin
   null;
end Main;

output (gnatmake)

$ gnatmake -gnatG main.adb 
gcc -c -gnatG main.adb
Source recreated from tree for Main (body)
------------------------------------------


procedure main is
   type f6 is delta 2#1.0#E-32 range 0.0 ..
     [18446744073709551615.0*2**(-32)];
   for f6'size use 64;
   [type Tf6B is delta 2#1.0#E-32 range
     -[9223372036854775808.0*2**(-32)] ..
     [9223372036854775807.0*2**(-32)]]
   freeze Tf6B []
   x : f6;
   y : Tf6B;
begin
   null;
end main;

main.adb:3:04: size required (65) for type "F6" too large, maximum allowed is 64
main.adb:3:09: warning: declared high bound of type "F6" is outside type range
main.adb:3:09: warning: high bound adjusted down by delta (RM 3.5.9(13))
gnatmake: "main.adb" compilation error
DeeDee
  • 5,654
  • 7
  • 14
  • My version of gnat (debian -- 8.3.0) does not output bounds :(, I got : `[type Tf6B is ???]` . I'll see how to update gnat ... – wondering-if Dec 23 '19 at 13:53
  • It should be similar for other types ... for example : `Tf3B` as the base type of `F3`should be symetric around `0` and its size should be `> 8`. That's not the case. Or else I'm missing something ... – wondering-if Dec 23 '19 at 13:59
  • Added gnat freeze process trace in the question. My interpretation so far is that gnat is fixing required size for the base type too soon: while the max size for Tf6B is 65 it should wait for the actual range of f6 before deciding if the needed size is out of bound. – wondering-if Dec 23 '19 at 14:46
  • @wondering-if I used GNAT CE 2019 to generate the output of GNATmake. GNAT FSF 8.3.0 indeed does not provide the same output. I'm not sure whether GNAT fixes the required size too soon. Although the compiler can satisfy the size clauses for the (sub)types like `f3` ... `f6`, I think that (based on the statements in the Ada RM) it just also must be able to represent the underlying (base)types (`Tf3B` ... `Tf6B`). This might also be related to [ARM 3.5 (6)](http://www.ada-auth.org/standards/12aarm/html/AA-3-5.html#p6). – DeeDee Dec 23 '19 at 15:43
  • @wondering-if Furthermore, please note that the language also allows you to actually reference this base type at any time using the aspect `'Base` (see updated example). Hence, as the base type must be available, it must also be representable. – DeeDee Dec 23 '19 at 16:30
  • As it seems a "legal ada problem", I'm not sure a definitive answer can be easily found . In the meantime I combined modular/interfaces.c types to implement my requirements ... – wondering-if Dec 23 '19 at 17:00
  • @wondering-if If you really want to know the details, then you might want to contact the [ARG](http://www.ada-auth.org/arg.html), but I think that the rationale for having base types was already described for Ada 83 (see e.g. section 7.4 of the [Ada 83 rationale](http://archive.adaic.com/standards/83rat/html/ratl-07-04.html#7.4)). The idea is that the compiler always chooses a hardware compatible (native) type from which the user-defined (sub)type is derived. – DeeDee Dec 23 '19 at 19:50
  • @wondering-if You could then ask why no unsigned integer could be chosen then for `F6`. I'm not sure. Maybe it's related to possible compiler complexity. In particular: if you would allow 0 to max positive unsigned range as it fits in a 64-bit register, then you would also want to support a max negative range to 0. And what about all intermediate non-symmetrical ranges that also fit into a 64-bit processor register. I think that this gets very complicated, especially when you need to perform (fixed-point) arithmetic. – DeeDee Dec 23 '19 at 19:50