Making the code compliant to the documentation about Floating Point

support default values for C/C++. FPP-MODEL=PRECISE enables
FFP-CONTRACT(FMA is enabled).

Fix for https://bugs.llvm.org/show_bug.cgi?id=50222
This commit is contained in:
Zahira Ammarguellat 2021-11-09 09:35:25 -05:00
parent 491beae71d
commit f04e387055
9 changed files with 262 additions and 36 deletions

View File

@ -202,6 +202,16 @@ Arm and AArch64 Support in Clang
architecture features, but will enable certain optimizations specific to
Cortex-A57 CPUs and enable the use of a more accurate scheduling model.
Floating Point Support in Clang
-------------------------------
- The -ffp-model=precise now implies -ffp-contract=on rather than
-ffp-contract=fast, and the documentation of these features has been
clarified. Previously, the documentation claimed that -ffp-model=precise was
the default, but this was incorrect because the precise model implied
-ffp-contract=fast, whereas the default behavior is -ffp-contract=on.
-ffp-model=precise is now exactly the default mode of the compiler.
Internal API Changes
--------------------

View File

@ -1260,8 +1260,49 @@ installed.
Controlling Floating Point Behavior
-----------------------------------
Clang provides a number of ways to control floating point behavior. The options
are listed below.
Clang provides a number of ways to control floating point behavior, including
with command line options and source pragmas. This section
describes the various floating point semantic modes and the corresponding options.
.. csv-table:: Floating Point Semantic Modes
:header: "Mode", "Values"
:widths: 15, 30, 30
"ffp-exception-behavior", "{ignore, strict, may_trap}",
"fenv_access", "{off, on}", "(none)"
"frounding-math", "{dynamic, tonearest, downward, upward, towardzero}"
"ffp-contract", "{on, off, fast, fast-honor-pragmas}"
"fdenormal-fp-math", "{IEEE, PreserveSign, PositiveZero}"
"fdenormal-fp-math-fp32", "{IEEE, PreserveSign, PositiveZero}"
"fmath-errno", "{on, off}"
"fhonor-nans", "{on, off}"
"fhonor-infinities", "{on, off}"
"fsigned-zeros", "{on, off}"
"freciprocal-math", "{on, off}"
"allow_approximate_fns", "{on, off}"
"fassociative-math", "{on, off}"
This table describes the option settings that correspond to the three
floating point semantic models: precise (the default), strict, and fast.
.. csv-table:: Floating Point Models
:header: "Mode", "Precise", "Strict", "Fast"
:widths: 25, 15, 15, 15
"except_behavior", "ignore", "strict", "ignore"
"fenv_access", "off", "on", "off"
"rounding_mode", "tonearest", "dynamic", "tonearest"
"contract", "on", "off", "fast"
"denormal_fp_math", "IEEE", "IEEE", "PreserveSign"
"denormal_fp32_math", "IEEE","IEEE", "PreserveSign"
"support_math_errno", "on", "on", "off"
"no_honor_nans", "off", "off", "on"
"no_honor_infinities", "off", "off", "on"
"no_signed_zeros", "off", "off", "on"
"allow_reciprocal", "off", "off", "on"
"allow_approximate_fns", "off", "off", "on"
"allow_reassociation", "off", "off", "on"
.. option:: -ffast-math
@ -1467,7 +1508,7 @@ Note that floating-point operations performed as part of constant initialization
and ``fast``.
Details:
* ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=fast``). This is the default behavior.
* ``precise`` Disables optimizations that are not value-safe on floating-point data, although FP contraction (FMA) is enabled (``-ffp-contract=on``). This is the default behavior.
* ``strict`` Enables ``-frounding-math`` and ``-ffp-exception-behavior=strict``, and disables contractions (FMA). All of the ``-ffast-math`` enablements are disabled. Enables ``STDC FENV_ACCESS``: by default ``FENV_ACCESS`` is disabled. This option setting behaves as though ``#pragma STDC FENV_ACESS ON`` appeared at the top of the source file.
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast``

View File

@ -2666,10 +2666,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath;
llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math;
StringRef FPContract = "";
// CUDA and HIP don't rely on the frontend to pass an ffp-contract option.
// If one wasn't given by the user, don't pass it here.
StringRef FPContract;
if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
!JA.isOffloading(Action::OFK_HIP))
FPContract = "on";
bool StrictFPModel = false;
if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
CmdArgs.push_back(A->getValue());
@ -2691,7 +2695,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
ReciprocalMath = false;
SignedZeros = true;
// -fno_fast_math restores default denormal and fpcontract handling
FPContract = "";
FPContract = "on";
DenormalFPMath = llvm::DenormalMode::getIEEE();
// FIXME: The target may have picked a non-IEEE default mode here based on
@ -2711,12 +2715,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// ffp-model= is a Driver option, it is entirely rewritten into more
// granular options before being passed into cc1.
// Use the gcc option in the switch below.
if (!FPModel.empty() && !FPModel.equals(Val)) {
if (!FPModel.empty() && !FPModel.equals(Val))
D.Diag(clang::diag::warn_drv_overriding_flag_option)
<< Args.MakeArgString("-ffp-model=" + FPModel)
<< Args.MakeArgString("-ffp-model=" + Val);
FPContract = "";
}
<< Args.MakeArgString("-ffp-model=" + FPModel)
<< Args.MakeArgString("-ffp-model=" + Val);
if (Val.equals("fast")) {
optID = options::OPT_ffast_math;
FPModel = Val;
@ -2724,7 +2726,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
} else if (Val.equals("precise")) {
optID = options::OPT_ffp_contract;
FPModel = Val;
FPContract = "fast";
FPContract = "on";
PreciseFPModel = true;
} else if (Val.equals("strict")) {
StrictFPModel = true;
@ -2812,9 +2814,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
case options::OPT_ffp_contract: {
StringRef Val = A->getValue();
if (PreciseFPModel) {
// -ffp-model=precise enables ffp-contract=fast as a side effect
// the FPContract value has already been set to a string literal
// and the Val string isn't a pertinent value.
// -ffp-model=precise enables ffp-contract=on.
// -ffp-model=precise sets PreciseFPModel to on and Val to
// "precise". FPContract is set.
;
} else if (Val.equals("fast") || Val.equals("on") || Val.equals("off"))
FPContract = Val;
@ -2907,23 +2909,27 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
AssociativeMath = false;
ReciprocalMath = false;
SignedZeros = true;
TrappingMath = false;
RoundingFPMath = false;
// -fno_fast_math restores default denormal and fpcontract handling
DenormalFPMath = DefaultDenormalFPMath;
DenormalFP32Math = llvm::DenormalMode::getIEEE();
FPContract = "";
if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
!JA.isOffloading(Action::OFK_HIP))
if (FPContract == "fast") {
FPContract = "on";
D.Diag(clang::diag::warn_drv_overriding_flag_option)
<< "-ffp-contract=fast"
<< "-ffp-contract=on";
}
break;
}
if (StrictFPModel) {
// If -ffp-model=strict has been specified on command line but
// subsequent options conflict then emit warning diagnostic.
if (HonorINFs && HonorNaNs &&
!AssociativeMath && !ReciprocalMath &&
SignedZeros && TrappingMath && RoundingFPMath &&
(FPContract.equals("off") || FPContract.empty()) &&
DenormalFPMath == llvm::DenormalMode::getIEEE() &&
DenormalFP32Math == llvm::DenormalMode::getIEEE())
if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath &&
SignedZeros && TrappingMath && RoundingFPMath &&
DenormalFPMath == llvm::DenormalMode::getIEEE() &&
DenormalFP32Math == llvm::DenormalMode::getIEEE() &&
FPContract.equals("off"))
// OK: Current Arg doesn't conflict with -ffp-model=strict
;
else {

View File

@ -1,9 +1,120 @@
// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=aarch64-apple-darwin -S -o - %s | FileCheck %s
// REQUIRES: aarch64-registered-target
// REQUIRES: x86-registered-target
// RUN: %clang_cc1 -triple=x86_64 %s -emit-llvm -o - \
// RUN:| FileCheck --check-prefixes CHECK,CHECK-DEFAULT %s
// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=off %s -emit-llvm -o - \
// RUN:| FileCheck --check-prefixes CHECK,CHECK-DEFAULT %s
// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=on %s -emit-llvm -o - \
// RUN:| FileCheck --check-prefixes CHECK,CHECK-ON %s
// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=fast %s -emit-llvm -o - \
// RUN:| FileCheck --check-prefixes CHECK,CHECK-CONTRACTFAST %s
// RUN: %clang_cc1 -triple=x86_64 -ffast-math %s -emit-llvm -o - \
// RUN:| FileCheck --check-prefixes CHECK,CHECK-CONTRACTOFF %s
// RUN: %clang_cc1 -triple=x86_64 -ffast-math -ffp-contract=off %s -emit-llvm \
// RUN: -o - | FileCheck --check-prefixes CHECK,CHECK-CONTRACTOFF %s
// RUN: %clang_cc1 -triple=x86_64 -ffast-math -ffp-contract=on %s -emit-llvm \
// RUN: -o - | FileCheck --check-prefixes CHECK,CHECK-ONFAST %s
// RUN: %clang_cc1 -triple=x86_64 -ffast-math -ffp-contract=fast %s -emit-llvm \
// RUN: -o - | FileCheck --check-prefixes CHECK,CHECK-FASTFAST %s
// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=fast -ffast-math %s \
// RUN: -emit-llvm \
// RUN: -o - | FileCheck --check-prefixes CHECK,CHECK-FASTFAST %s
// RUN: %clang_cc1 -triple=x86_64 -ffp-contract=off -fmath-errno \
// RUN: -fno-rounding-math %s -emit-llvm -o - \
// RUN: -o - | FileCheck --check-prefixes CHECK,CHECK-NOFAST %s
// RUN: %clang -S -emit-llvm -fno-fast-math %s -o - \
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-ON
// RUN: %clang -S -emit-llvm -ffp-contract=fast -fno-fast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-ON
// RUN: %clang -S -emit-llvm -ffp-contract=on -fno-fast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-ON
// RUN: %clang -S -emit-llvm -ffp-contract=off -fno-fast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-OFF
// RUN: %clang -S -emit-llvm -ffp-model=fast -fno-fast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-ON
// RUN: %clang -S -emit-llvm -ffp-model=precise -fno-fast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-ON
// RUN: %clang -S -emit-llvm -ffp-model=strict -fno-fast-math \
// RUN: -target x86_64 %s -o - | FileCheck %s \
// RUN: --check-prefixes=CHECK,CHECK-FPSC-OFF
// RUN: %clang -S -emit-llvm -ffast-math -fno-fast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-FPC-ON
float mymuladd(float x, float y, float z) {
// CHECK: define{{.*}} float @mymuladd
return x * y + z;
// expected-warning{{overriding '-ffp-contract=fast' option with '-ffp-contract=on'}}
// CHECK-DEFAULT: load float, float*
// CHECK-DEFAULT: fmul float
// CHECK-DEFAULT: load float, float*
// CHECK-DEFAULT: fadd float
// CHECK-ON: load float, float*
// CHECK-ON: load float, float*
// CHECK-ON: load float, float*
// CHECK-ON: call float @llvm.fmuladd.f32(float {{.*}}, float {{.*}}, float {{.*}})
// CHECK-CONTRACTFAST: load float, float*
// CHECK-CONTRACTFAST: load float, float*
// CHECK-CONTRACTFAST: fmul contract float
// CHECK-CONTRACTFAST: load float, float*
// CHECK-CONTRACTFAST: fadd contract float
// CHECK-CONTRACTOFF: load float, float*
// CHECK-CONTRACTOFF: load float, float*
// CHECK-CONTRACTOFF: fmul reassoc nnan ninf nsz arcp afn float
// CHECK-CONTRACTOFF: load float, float*
// CHECK-CONTRACTOFF: fadd reassoc nnan ninf nsz arcp afn float {{.*}}, {{.*}}
// CHECK-ONFAST: load float, float*
// CHECK-ONFAST: load float, float*
// CHECK-ONFAST: load float, float*
// CHECK-ONFAST: call reassoc nnan ninf nsz arcp afn float @llvm.fmuladd.f32(float {{.*}}, float {{.*}}, float {{.*}})
// CHECK-FASTFAST: load float, float*
// CHECK-FASTFAST: load float, float*
// CHECK-FASTFAST: fmul fast float
// CHECK-FASTFAST: load float, float*
// CHECK-FASTFAST: fadd fast float {{.*}}, {{.*}}
// CHECK-NOFAST: load float, float*
// CHECK-NOFAST: load float, float*
// CHECK-NOFAST: fmul float {{.*}}, {{.*}}
// CHECK-NOFAST: load float, float*
// CHECK-NOFAST: fadd float {{.*}}, {{.*}}
// CHECK-FPC-ON: load float, float*
// CHECK-FPC-ON: load float, float*
// CHECK-FPC-ON: load float, float*
// CHECK-FPC-ON: call float @llvm.fmuladd.f32(float {{.*}}, float {{.*}}, float {{.*}})
// CHECK-FPC-OFF: load float, float*
// CHECK-FPC-OFF: load float, float*
// CHECK-FPC-OFF: fmul float
// CHECK-FPC-OFF: load float, float*
// CHECK-FPC-OFF: fadd float {{.*}}, {{.*}}
// CHECK-FFPC-OFF: load float, float*
// CHECK-FFPC-OFF: load float, float*
// CHECK-FPSC-OFF: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, {{.*}})
// CHECK-FPSC-OFF: load float, float*
// CHECK-FPSC-OFF: [[RES:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, {{.*}})
float fma_test1(float a, float b, float c) {
// CHECK: fmadd
float x = a * b;
float y = x + c;
return y;
}

View File

@ -0,0 +1,48 @@
// REQUIRES: x86-registered-target
// RUN: %clang -S -emit-llvm -ffp-model=fast -emit-llvm %s -o - \
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-FAST
// RUN: %clang -S -emit-llvm -ffp-model=precise %s -o - \
// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-PRECISE
// RUN: %clang -S -emit-llvm -ffp-model=strict %s -o - \
// RUN: -target x86_64 | FileCheck %s --check-prefixes=CHECK,CHECK-STRICT
// RUN: %clang -S -emit-llvm -ffp-model=strict -ffast-math \
// RUN: -target x86_64 %s -o - | FileCheck %s \
// RUN: --check-prefixes CHECK,CHECK-STRICT-FAST
// RUN: %clang -S -emit-llvm -ffp-model=precise -ffast-math \
// RUN: %s -o - | FileCheck %s --check-prefixes CHECK,CHECK-FAST1
float mymuladd(float x, float y, float z) {
// CHECK: define{{.*}} float @mymuladd
return x * y + z;
// CHECK-FAST: fmul fast float
// CHECK-FAST: load float, float*
// CHECK-FAST: fadd fast float
// CHECK-PRECISE: load float, float*
// CHECK-PRECISE: load float, float*
// CHECK-PRECISE: load float, float*
// CHECK-PRECISE: call float @llvm.fmuladd.f32(float {{.*}}, float {{.*}}, float {{.*}})
// CHECK-STRICT: load float, float*
// CHECK-STRICT: load float, float*
// CHECK-STRICT: call float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, {{.*}})
// CHECK-STRICT: load float, float*
// CHECK-STRICT: call float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, {{.*}})
// CHECK-STRICT-FAST: load float, float*
// CHECK-STRICT-FAST: load float, float*
// CHECK-STRICT-FAST: call fast float @llvm.experimental.constrained.fmul.f32(float {{.*}}, float {{.*}}, {{.*}})
// CHECK-STRICT-FAST: load float, float*
// CHECK-STRICT-FAST: call fast float @llvm.experimental.constrained.fadd.f32(float {{.*}}, float {{.*}}, {{.*}}
// CHECK-FAST1: load float, float*
// CHECK-FAST1: load float, float*
// CHECK-FAST1: fmul fast float {{.*}}, {{.*}}
// CHECK-FAST1: load float, float* {{.*}}
// CHECK-FAST1: fadd fast float {{.*}}, {{.*}}
}

View File

@ -2,9 +2,9 @@
// REQUIRES: powerpc-registered-target
// RUN: %clang -S -emit-llvm -target powerpc64-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \
// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE
// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE
// RUN: %clang -S -emit-llvm -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \
// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE
// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE
// CHECK-BE-DAG: @_mm_movemask_pd.perm_mask = internal constant <4 x i32> <i32 -2139062144, i32 -2139062144, i32 -2139062144, i32 -2139078656>, align 16
// CHECK-BE-DAG: @_mm_shuffle_epi32.permute_selectors = internal constant [4 x i32] [i32 66051, i32 67438087, i32 134810123, i32 202182159], align 4

View File

@ -2,11 +2,11 @@
// REQUIRES: powerpc-registered-target
// RUN: %clang -S -emit-llvm -target powerpc64-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \
// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE
// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-BE
// RUN: %clang -x c++ -fsyntax-only -target powerpc64-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \
// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns
// RUN: %clang -S -emit-llvm -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \
// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE
// RUN: -ffp-contract=off -fno-discard-value-names -mllvm -disable-llvm-optzns -o - | llvm-cxxfilt -n | FileCheck %s --check-prefixes=CHECK,CHECK-LE
// RUN: %clang -x c++ -fsyntax-only -target powerpc64le-unknown-linux-gnu -mcpu=pwr8 -ffreestanding -DNO_WARN_X86_INTRINSICS %s \
// RUN: -fno-discard-value-names -mllvm -disable-llvm-optzns

View File

@ -99,7 +99,7 @@
// RUN: %clang -### -nostdinc -ffp-model=precise -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FPM-PRECISE %s
// CHECK-FPM-PRECISE: "-cc1"
// CHECK-FPM-PRECISE: "-ffp-contract=fast"
// CHECK-FPM-PRECISE: "-ffp-contract=on"
// CHECK-FPM-PRECISE: "-fno-rounding-math"
// RUN: %clang -### -nostdinc -ffp-model=strict -c %s 2>&1 \

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -O3 -ffp-contract=fast -triple=aarch64-apple-darwin \
// RUN: -S -o - %s | FileCheck --check-prefix=CHECK-FMADD %s
// REQUIRES: aarch64-registered-target
float fma_test1(float a, float b, float c) {
// CHECK-FMADD: fmadd
float x = a * b;
float y = x + c;
return y;
}