High application performance is an important goal of the Intel® Compilers, even at default optimization levels. A number of optimizations involve transformations, such as evaluation of constant expressions at compiler time, hoisting invariant expressions out of loops, or changes in the order of evaluation of expressions. These optimizations usually help the compiler produce most efficient code possible. However, this may not be true for floating-point applications, because some optimizations may affect accuracy, reproducibility, and performance. In addition, some optimizations are not consistent with strict interpretation of the ANSI or ISO standards for C and C++, which can result in differences in rounding and small variants in floating-point results that may be more or less accurate than the ANSI-conformant result.
Intel Compilers provide the -fp-model (Linux* and Mac OS*) or /fp (Windows*) option, which allows you to control the optimizations performed when you build an application. The option allows you to specify the compiler rules for:
Value safety: Whether the compiler may perform transformations that could affect the result. For example, in the SAFE mode, the compiler won't transform x/x to 1.0. The UNSAFE mode is the default.
Floating-point expression evaluation: How the compiler should handle the rounding of intermediate expressions. For example, when double precision is specified, the compiler may transform the statement t0=4.0f+0/1f+t1+t2; to t0=(float)(4.1+(double)t1+(double)t2);
Floating-point contractions: Whether the compiler should generate floating-point multiply-add (FMA) on processors based on the IA-64 architecture. When enabled, the compiler may generate FMA for combined multiply/add; when disabled, the compiler must generate separate multiply/add with intermediate rounding.
Floating-point environment access: Whether the compiler must account for the possibility that the program might access the floating-point environment, either by changing the default floating-point control settings or by reading the floating-point status flags. This is disabled by default. You can use the -fp-model:strict (Linux and Mac OS) /fp:strict (Windows) option to enable it.
Precise floating-point exceptions: Whether the
compiler should account for the possibility that floating-point operations
might produce an exception. This is disabled by default. You can use -fp-model:strict (Linux and Mac OS) or /fp:strict
(Windows); or -fp-model:except (Linux and Mac
OS) or /fp:except (Windows) to enable it.
Consider the following example:
double a=1.5;
int x=0;
...
__try {
int t0=a; //raises inexact
x=1;
a*=2;
} __except(1) {
printf("SEH Exception: x=%d\n", x);
}
Without precise floating-point exceptions, the result is SEH Exception: x=1; with precision floating-point exceptions, the result is SEH Exception: x=0.
The following table describes the impact of different keywords of the option on compiler rules and optimizations:
|
Value |
Floating-Point Expression Evaluation |
Floating-Point Contractions |
Floating-Point Environment Access |
Precise Floating-Point Exceptions |
precise |
Safe |
Varies |
Yes |
No |
No |
strict |
Safe |
Varies |
No |
Yes |
Yes |
fast=1 (default) |
Unsafe |
Unknown |
Yes |
No |
No |
fast=2 |
Very unsafe |
Unknown |
Yes |
No |
No |
except |
Unaffected |
Unaffected |
Unaffected |
Unaffected |
Yes |
It is illegal to specify the except keyword in an unsafe safety mode.
Based on the objectives of an application, you can choose to use different sets of compiler options and keywords to enable or disable certain optimizations, so that you can get the desired result.