This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C99 and i387 Floating-point assignments


Volker Reichelt wrote:
> On 21 Aug, Jim Wilson wrote:
> I got confused by your usage of the word truncated. In the example with the
> full FP stack you used "truncated" as a synononym for "rounded", right?
> And you wanted to say that after some intermediate results no rounding is
> done (no rounding to 64 bits that is, you have to round to 80 bits of course),
> and after some results (apparently correct) rounding to 64 bit is done.
>
>>It is the same fst/fstp instruction, so it is the same rounding.
>>
>>>But I think the difference between rounding and truncating is not the
>>>problem for the users.
>>
>>The problem isn't that the value is rounded.  The problem is that the
>>value is rounded at unpredictable locations,
>
> Agreed. But that's not a bug IMHO.

When the unpredictable locations include the left-hand-sides of
assignments specified in the program text, this seems to me to fail
to comply with the language definition (for C) of assignments.

It seems to me that the definition of assignments in C99 makes
conversion to the user-specified format a language requirement independently
of whether the rounding on the right-hand-side makes any kind of sense or not.

The definition of assignments also seems (to me) to forbid
promotion of stack locals to long double.  Promoting stack locals
also makes for unpredictability, since changing a variable used as a function
parameter from pass-by-value-to pass-by-reference could change the value of the
variable, and of dependent expressions.


Consider the program:


float a = (float) (1L << 30);

int main()
{
  float b = a + (float)1;
  printf( "b = %11F\n", b );
  return 0;
}

With gcc3.3 on athlon-pc-linux-gnu, and -O1, this prints: "b = 1073741825.000000",
a value which is not representable as a float.  Any float of magnitude close
to 2^30 mast have a value which is an even integer, since floats have
only 24 bits of precision.  So the value printed is certainly not the
value of any object of type float.
With -O0, "b = 1073741824.000000" is printed: this one of
the two possible results which seem to me to be permitted by C99.


A similiar error with integer arithmetic might make this program print "c = 1025":

int i = 1024;

int main()
{
  char c = i + 1;
  printf( "c = %d\n", c );
  return 0;
}


The nature of the lies in i386.md do not currently mean that floating point format conversion by store-and-reload never happens without -ffloat-store.

Store-and-reload is used already when a floating value notionally computed at one
precision is converted to a narrower precision.


So this:


float float_si_sf_A( int i )
{
  double a = i; // All ints are exactly representable as double
  return a;     // conversion to float here
}

Will always return a value representable as a float (with gcc-3.3),


However this:


float float_si_sf_B( int i )
{
  float a = i;  // Rounding required for |i| > 2^24
  return a;     // No conversion here.
}

Won't, at -O1 or higher, because i386.md pretends that the fildl instruction
converts a 32-bit int to a float, when really it converts it to long double.

So this program prints "Eeek!" 50 times:

int main()
{
  int i;
  for( i = 1 << 30; i < (1 << 30) + 100; ++i )
  {
    float a = float_si_sf_B( i );
    int j = a;

    if( (i & 1) && i == j )
      printf( "Eeek! %d\n", i );
  }
  return 0;
}



Regards,

John.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]