Bug 37845 - gcc ignores FP_CONTRACT pragma set to OFF
Summary: gcc ignores FP_CONTRACT pragma set to OFF
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on: 37846
Blocks:
  Show dependency treegraph
 
Reported: 2008-10-16 07:38 UTC by Vincent Lefèvre
Modified: 2019-06-26 05:33 UTC (History)
3 users (show)

See Also:
Host:
Target: ia64-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-10-16 09:40:12


Attachments
[GCOV] Wrong frequencies when a global variable is in a while expression in gcov (64 bytes, text/plain)
2019-01-18 16:01 UTC, Anonymous
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2008-10-16 07:38:03 UTC
To be conform to the ISO C standard (when FLT_EVAL_METHOD is 0, 1 or 2, which is the case of gcc), gcc should either take FP_CONTRACT pragmas into account or (in the mean time) assume they are set to OFF, i.e. disallow the contraction of floating expressions. This means in particular that -mno-fused-madd should be the default (with processors for which this option is supported, e.g. PowerPC).

I've tested with gcc-4.4-20081010 on ia64 that this bug is still present.
Comment 1 Richard Biener 2008-10-16 09:40:12 UTC
Confirmed.  The FP_CONTRACT macro is not implemented, but the default behavior
of GCC is to behave like it was set to OFF.

This is a target issue (sofar ia64 is identified as buggy).
Comment 2 Richard Biener 2008-10-16 09:42:58 UTC
The fma patterns on ia64 are not guarded properly.  They should be off
as long as flag_unsafe_math_optimizations is not specified.
Comment 3 Vincent Lefèvre 2008-10-16 13:54:56 UTC
(In reply to comment #1)
> Confirmed.  The FP_CONTRACT macro is not implemented, but the default behavior
> of GCC is to behave like it was set to OFF.

The problem is that on PowerPC, x*y+z is fused (contracted) by default (which is forbidden when FP_CONTRACT is OFF). I could test only with Apple's gcc 4.0.1, but the man page of the gcc snapshot implies that the problem remains with the current versions:

   IBM RS/6000 and PowerPC Options

   -mfused-madd
   -mno-fused-madd
       Generate code that uses (does not use) the floating point multiply
       and accumulate instructions.  These instructions are generated by
       default if hardware floating is used.

But the correct behavior would be that these instructions should not be generated by default.

On http://www.vinc17.org/software/tst-ieee754.c compiled with

  gcc -Wall -O2 -std=c99 tst-ieee754.c -o tst-ieee754 -lm

I get:

$ ./tst-ieee754 | grep fused
x * y + z with FP_CONTRACT OFF is fused.

I need to add -mno-fused-madd to get the correct behavior:

$ ./tst-ieee754 | grep fused
x * y + z with FP_CONTRACT OFF is not fused.
Comment 4 pinskia@gmail.com 2008-10-16 15:40:46 UTC
Subject: Re:  gcc ignores FP_CONTRACT pragma set to OFF



Sent from my iPhone

On Oct 16, 2008, at 2:42 AM, "rguenth at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org 
 > wrote:

>
>
> ------- Comment #2 from rguenth at gcc dot gnu dot org  2008-10-16  
> 09:42 -------
> The fma patterns on ia64 are not guarded properly.  They should be off
> as long as flag_unsafe_math_optimizations is not specified.

No that is not true. They should be on by default.

>
>
>
> -- 
>
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37845
>
Comment 5 joseph@codesourcery.com 2008-10-16 16:31:44 UTC
Subject: Re:  gcc ignores FP_CONTRACT pragma set to OFF

On Thu, 16 Oct 2008, rguenth at gcc dot gnu dot org wrote:

> Confirmed.  The FP_CONTRACT macro is not implemented, but the default behavior
> of GCC is to behave like it was set to OFF.

No, the default is to behave like it is ON, on targets with fused 
operations, with target-specific options to turn it off.  A default of ON 
is fine according to C99.

It so happens that GCC's version of "ON" is buggy, in that it contracts 
even outside the bounds of source language expressions - those boundaries 
are lost at gimplification, long before the insn patterns are applied.  
Fixing this would probably require fused operations to be identified in 
the front end in conforming mode, and the only insn patterns in conforming 
mode for the fused instructions to have RTL describing them precisely as 
fused operations so non-fused ones don't get combined.

This situation is much like the other floating-point pragmas:

* GCC doesn't support any of the pragmas, and doesn't claim to support 
those parts of C99; the features can only be enabled or disabled for a 
whole translation unit on the command line.

* The features for a whole translation unit are in practice rather buggy 
and incomplete.  -fno-cx-limited-range (on by default) doesn't work for 
constant arithmetic (bug 30789).  -ftrapping-math (on by default) doesn't 
cause all required exceptions to be generated, and spurious exceptions are 
generated in some cases; no real effort has been made to get it to work 
properly in all cases.  -frounding-math (off by default) comes with a 
specific warning in the manual that it's experimental and incomplete, 
which is quite correct.

Yes, there should be a target-independent option to disable contracting 
rather than needing separate options for each target, and in conformance 
mode (flag_iso) contracting, if enabled, should be restricted to source 
language expressions.  I'm not aware of anyone working on this, or on the 
other issues with the options approximating to the standard pragmas, or on 
the pragmas themselves.

Comment 6 Vincent Lefèvre 2015-08-14 15:08:19 UTC
This bug has been fixed by:

r204460 | jsm28 | 2013-11-06 17:52:47 +0100 (Wed, 06 Nov 2013) | 9 lines
Changed paths:
   M /trunk/gcc/c-family/ChangeLog
   M /trunk/gcc/c-family/c-cppbuiltin.c
   M /trunk/gcc/c-family/c-opts.c
   M /trunk/gcc/testsuite/ChangeLog
   A /trunk/gcc/testsuite/gcc.dg/torture/c99-contract-1.c

c-family:
        * c-opts.c (c_common_post_options): Set -ffp-contract=off in C
        standards modes.
        * c-cppbuiltin.c (cpp_iec_559_value): Consider -ffp-contract=fast
        to mean lack of IEEE 754 support.

testsuite:
        * gcc.dg/torture/c99-contract-1.c: New test.

gcc/c-family/c-opts.c now contains:

  /* ISO C restricts floating-point expression contraction to within
     source-language expressions (-ffp-contract=on, currently an alias
     for -ffp-contract=off).  */
  if (flag_iso
      && !c_dialect_cxx ()
      && (global_options_set.x_flag_fp_contract_mode
          == (enum fp_contract_mode) 0)
      && flag_unsafe_math_optimizations == 0)
    flag_fp_contract_mode = FP_CONTRACT_OFF;

I tested, and this works as expected.

Note: This bug was about FP contraction being done despite the use of:
#pragma STDC FP_CONTRACT OFF
not about the pragma being ignored (the implementation of this pragma is not required by the ISO C standard if the default is OFF, which is now the case with GCC). So, this bug is really fixed. A new enhancement bug could be opened (if not already done) for the implementation of the STDC FP_CONTRACT pragma.
Comment 7 Anonymous 2019-01-18 16:01:46 UTC
Created attachment 45464 [details]
[GCOV] Wrong frequencies when a global variable is in a while expression in gcov

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.3.0-27ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)

$ cat small.c
int b;

void main()
{
    int c = 0;
    while (b) {
        c = 1;
    }
}

$ gcc small.c --coverage; ./a.out; gcov small.c; cat small.c.gcov
File 'small.c'
Lines executed:80.00% of 5
Creating 'small.c.gcov'

        -:    0:Source:small.c
        -:    0:Graph:small.gcno
        -:    0:Data:small.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:int b;
        -:    2:
        1:    3:void main()
        -:    4:{
        1:    5:    int c = 0;
        2:    6:    while (b) {
    #####:    7:        c = 1;
        -:    8:    }
        1:    9:}


We can find that Line #6 is wrongly marked as executed twice.