Bug 92875 - GCC ignores the floating-point 'f' suffix in C11 mode
Summary: GCC ignores the floating-point 'f' suffix in C11 mode
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 114050 114740 (view as bug list)
Depends on: 323
Blocks:
  Show dependency treegraph
 
Reported: 2019-12-09 19:51 UTC by anders@wahrzeichnen.de
Modified: 2024-04-16 12:48 UTC (History)
4 users (show)

See Also:
Host:
Target: i?86-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
test case with return value 0 or 8 expected, returns 12 (150 bytes, text/plain)
2019-12-09 19:51 UTC, anders@wahrzeichnen.de
Details

Note You need to log in before you can comment on or make changes to this bug.
Description anders@wahrzeichnen.de 2019-12-09 19:51:41 UTC
Created attachment 47454 [details]
test case with return value 0 or 8 expected, returns 12

GCC treats floating-point constants suffixed with 'f' as double, when compiled with either -std=c11 or -std=c18. The attached test case illustrates this problem: There are four functions f0, f1, f2, and f3. The first three functions f0, f1, and f2 should all compile to the same code, f4 is different and there for reference.

It turns out that with -std=387 and -m32 (or with -mfpmath=387), GCC compiles f0 and f1 to equivalent asm but not f2. Instead, it creates the same asm for f2 as for f3, involving some loading a constant into an FPU register using double precision. Apparently, writing '0.1f' is not enough to convince GCC that the constant is single precision.

This can be seen with the attached program:
$ gcc -O -m32 testcase.c  &&  ./a.out; echo $? 
8
$ gcc -std=c11 -O -m32 testcase.c  &&  ./a.out; echo $? 
12

The result should be either 0, 8, or 15, depending on how exactly the decimal constant 0.1 is rounded to binary floating-point, but it should never be anything else.

The bug seems to be independent of optimization; it happens with -O0, -O1, -O2, -O3, -Os, and -Og. I can trace it from GCC 9.2 all the way back to 4.8.4. It can be triggered on 387 (with -m32 or -mfpmath=387).
Comment 1 Andrew Pinski 2019-12-09 19:57:31 UTC
Does -ffloat-store help?
See 323 also.
Comment 2 anders@wahrzeichnen.de 2019-12-09 22:40:08 UTC
No, -ffloat-store does not help. And this has little if anything to do with 323, imho.

The asm generated for f3 is instructive: There, GCC wants to load a double constant 0x3fb999999999999a into the 387 FPU, which is 0.10000000000000000555... The single-precision constant t passed as argument to f0...f3 is 0x3dcccccd, which is 0.10000000149... So, it's no wonder that f3 returns 1; after all 0.10000000149 > 0.10000000000000000555.

The questions are: Why does the code generated for f2 try to load a double constant even if it is explicitly suffixed 'f'? Why should casting to (float) help? Why does std=c11 or c18 change the game?
Comment 3 jsm-csl@polyomino.org.uk 2019-12-09 22:40:59 UTC
The value of FLT_EVAL_METHOD applies to constants as well as to 
operations.  That is, when FLT_EVAL_METHOD == 2, 0.1f has the precision of 
long double but the semantic type of float, and 0.1 has the precision of 
long double but the semantic type of double.  An explicit cast to float 
removes excess precision.  This is as specified in the C standard.
Comment 4 anders@wahrzeichnen.de 2019-12-09 22:49:49 UTC
I don't know about other archs, but on amd64, GCC emits comiss insns (SSE2 single-precision scalar compare) for f0, f1, and f2 and comisd insns (SSE2 double-precision scalar compare) for f3. So this is evidently not a problem on amd64 (i.e. it does not depend on how the decimal-to-binary rounding was done for the value 0.1). Conclusion: Ignoring the 'f' suffix seems to be specific for 387.
Comment 5 jsm-csl@polyomino.org.uk 2019-12-09 23:12:13 UTC
Most architectures use FLT_EVAL_METHOD == 0.  It's specific to x87 (and 
older m68k) that FLT_EVAL_METHOD == 2 because x87 doesn't support direct 
arithmetic on float or double.  Lack of direct float and double arithmetic 
requires FLT_EVAL_METHOD == 2 and FLT_EVAL_METHOD == 2 requires 
interpreting floating constants to the range and precision of long double, 
whatever their semantic type.
Comment 6 anders@wahrzeichnen.de 2019-12-09 23:19:51 UTC
(In reply to joseph@codesourcery.com from comment #3)
> This is as specified in the C standard.

I guess you are referring to the C18 section

  6.3.1.8 (2) "The values of floating operands and of the results of floating expressions may be represented in greater range and precision than that required by the type; the types are not changed thereby. --footnote: The cast and assignment operators are still required to remove extra range and precision."

in conjunction with

  6.6 (5) "An expression that evaluates to a constant is required in several contexts. If a floating expression is evaluated in the translation environment, the arithmetic range and precision shall be at least as great as if the expression were being evaluated in the execution environment. --footnote: The use of evaluation formats as characterized by FLT_EVAL_METHOD also applies to evaluation in the translation environment."

If so, I propose to close this bug (as __FLT_EVAL_METHOD__ is indeed 2).
Comment 7 Vincent Lefèvre 2019-12-09 23:20:53 UTC
(In reply to joseph@codesourcery.com from comment #5)
> Lack of direct float and double arithmetic requires FLT_EVAL_METHOD == 2

No, FLT_EVAL_METHOD could also be negative, in which case GCC would be allowed to evaluate floating-point constants of type float in whatever range and precision it wishes.
Comment 8 Vincent Lefèvre 2019-12-09 23:24:13 UTC
(In reply to anders@wahrzeichnen.de from comment #6)
>   6.6 (5) "An expression that evaluates to a constant is required in several
> contexts. If a floating expression is evaluated in the translation
> environment, the arithmetic range and precision shall be at least as great
> as if the expression were being evaluated in the execution environment.
> --footnote: The use of evaluation formats as characterized by
> FLT_EVAL_METHOD also applies to evaluation in the translation environment."

This is about constant expressions and is not applicable to constants. See 5.2.4.2.2p9 for constants.
Comment 9 Eric Gallager 2020-02-07 04:15:33 UTC
due to the part about floating/double constant suffixes, I think bug 84717 is related
Comment 10 jsm-csl@polyomino.org.uk 2020-02-07 18:11:36 UTC
This has nothing to do with 84717.  The present bug is simply invalid; GCC 
is acting as specified in the C standard for excess precision.  84717 is 
arguably a legitimate issue about lack of documentation for an extension 
(albeit an extension taken from an old TR).
Comment 11 Andrew Pinski 2024-03-25 22:21:59 UTC
Invalid as explained
Comment 12 Andrew Pinski 2024-04-16 12:47:41 UTC
*** Bug 114050 has been marked as a duplicate of this bug. ***
Comment 13 Andrew Pinski 2024-04-16 12:48:05 UTC
*** Bug 114740 has been marked as a duplicate of this bug. ***