9

I have a question regarding the -ffp-contract flag in GNU GCC (see https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html).

The flag documentation is written as follows:

-ffp-contract=off disables floating-point expression contraction. -ffp-contract=fast enables floating-point expression contraction such as forming of fused multiply-add operations if the target has native support for them. -ffp-contract=on enables floating-point expression contraction if allowed by the language standard. This is currently not implemented and treated equal to -ffp-contract=off. The default is -ffp-contract=fast.

Now the question:

  • What is the difference between fast and on?
  • Is there any other contraction example beside the FMA (or similar like the fused-mult sub)?

1 Answers1

11

In C89, FP contraction is disallowed. Starting with C99, an implementation may do FP contraction of expressions by default, but would then be required to provide a #pragma STDC FP_CONTRACT (cppreference) which can be toggled to influence contraction behavior.

So the GCC switch was supposed to be:

  • -ffp-contract=off: Don't do contraction. Ignore #pragma STDC FP_CONTRACT. This is the default for -std=c89.
  • -ffp-contract=on: Enable contraction by default and honor #pragma STDC FP_CONTRACT. This would be the default for -std=c99 and above.
  • -ffp-contract=fast: This is the GCC default, even without any fast-math options. We don't claim ISO conformance in fast-math mode, so it's ok to always contract, even separate expressions (See Marc Glisse's comment). This is the default for -std=gnu99 and other GNU dialects of C.

Unfortunately, #pragma STDC FP_CONTRACT is not yet implemented in GCC, so for now gcc -ffp-contract=on does what is necessary to stay ISO-conforming: nothing. i.e. on = off, because the only other behaviour GCC knows how to implement (fast) is too aggressive for on.

You'd have to dig into the sources (or mailing list) to see what kind of contractions GCC is able to do, but it doesn't have to be limited to FMA.

See GCC and Clang on Godbolt for a simple testcase of one expression vs. 2 statements. Clang defaults to -ffp-contract=off but supports on and fast, as you can see. GCC only supports off and fast, with on mapping to off.


What the C11 standard has to say about #pragma STDC FP_CONTRACT:

§6.5¶8: A floating expression may be contracted , that is, evaluated as though it were a single operation, thereby omitting rounding errors implied by the source code and the expression evaluation method.89) The FP_CONTRACT pragma in <math.h> provides a way to disallow contracted expressions. Otherwise, whether and how expressions are contracted is implementation-defined.90)

  1. The intermediate operations in the contracted expression are evaluated as if to infinite range and precision, while the final operation is rounded to the format determined by the expression evaluation method. A contracted expression might also omit the raising of floating-point exceptions.

  2. This license is specifically intended to allow implementations to exploit fast machine instructions that combine multiple C operators. As contractions potentially undermine predictability, and can even decrease accuracy for containing expressions, their use needs to be well-defined and clearly documented.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
a3f
  • 8,517
  • 1
  • 41
  • 46
  • 3
    `a*a*a*a*a*a` is not treated as a contraction by gcc. Also, with everything implemented, "on" would optimize `x=2*x+3` to fma but "fast" would be required to contract `x*=2;x+=3` (not a single expression). – Marc Glisse Apr 12 '17 at 20:46
  • @MarcGlisse Thanks for the correction. I amended the answer. – a3f Apr 12 '17 at 21:04
  • GCC behaves like `-ffp-contract=fast` by default, even with `-fno-fast-math`. https://godbolt.org/z/6UzQHP. – Peter Cordes Nov 19 '19 at 07:44
  • 1
    @PeterCordes -ffp-contract=fast is the default for -std=gnu17 but not for -std=c17 (the strict mode). – Marc Glisse Nov 19 '19 at 14:30
  • @MarcGlisse: Good point; I was just thinking in terms of the overall default because `-std=gnu(something)` is the default for that option. Is this answer misleading now? – Peter Cordes Nov 19 '19 at 19:12
  • About `Clang defaults to -ffp-contract=off`. Clang's documentation says: `-ffp-contract=on (according to FP_CONTRACT pragma, default)`. `clang -cc1 --help | grep contract` says the same. – pmor Sep 13 '20 at 16:38
  • @pmor: clang `-O3 -march=skylake` doesn't contract `a*b+3` into an FMA even within a single statement, but it does with `-ffp-contract=on` (bottom right output pane on https://godbolt.org/z/eW499xno4 vs. bottom left). I tried clang 9.0 and clang nightly trunk, and a couple earlier versions. So the behaviour with no extra options matches `-ffp-contract=off`. – Peter Cordes Aug 22 '21 at 00:32
  • @PeterCordes Interesting. Try to add `#pragma STDC FP_CONTRACT OFF` and see that gcc (9.2 and trunk) still contracts: `vfmadd213ss` is generated. Per C11, 7.12.2 `FP_CONTRACT OFF` _can be used_ (i.e. not _shall_) to "disallow the implementation to contract expressions". – pmor Aug 25 '21 at 17:29
  • @pmor: yeah, I guess current GCC doesn't support the pragma at all, only command line options. – Peter Cordes Aug 25 '21 at 17:33
  • @PeterCordes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37845 – pmor Aug 25 '21 at 17:37
  • @pmor: Yup, they decided that having `-std=c99` imply fp-contract=off (instead of the default gnu99 -> on) was sufficient to comply with the C standard, so closed the bug. If you carefully read the comment at the bottom of the comment with the commit, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37845#c6 , Vincent points out that that bug wasn't about lack of support for the pragma per-se, and that would be a separate enhancement request which someone could open. – Peter Cordes Aug 25 '21 at 19:02