Skip to content

Commit 2c93e3c

Browse files
committed
Take math-errno into account with '#pragma float_control(precise,on)' and
'attribute__((optnone)). Differential Revision: https://reviews.llvm.org/D151834
1 parent 77054f3 commit 2c93e3c

File tree

9 files changed

+166
-9
lines changed

9 files changed

+166
-9
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4708,7 +4708,12 @@ settings can be pushed or popped.
47084708
When ``pragma float_control(precise, on)`` is enabled, the section of code
47094709
governed by the pragma uses precise floating point semantics, effectively
47104710
``-ffast-math`` is disabled and ``-ffp-contract=on``
4711-
(fused multiply add) is enabled.
4711+
(fused multiply add) is enabled. This pragma enables ``-fmath-errno``.
4712+
4713+
When ``pragma float_control(precise, off)`` is enabled, unsafe-floating point
4714+
optimizations are enabled in the section of code governed by the pragma.
4715+
Effectively ``-ffast-math`` is enabled and ``-ffp-contract=fast``. This pragma
4716+
disables ``-fmath-errno``.
47124717
47134718
When ``pragma float_control(except, on)`` is enabled, the section of code
47144719
governed by the pragma behaves as though the command-line option

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ Floating Point Support in Clang
365365
- Add ``__builtin_elementwise_bitreverse`` builtin for integer types only.
366366
- Add ``__builtin_elementwise_sqrt`` builtin for floating point types only.
367367
- ``__builtin_isfpclass`` builtin now supports vector types.
368+
- ``#pragma float_control(precise,on)`` enables precise floating-point
369+
semantics. If ``math-errno`` is disabled in the current TU, clang will
370+
re-enable ``math-errno`` in the presense of
371+
``#pragma float_control(precise,on)``.
368372

369373
AST Matchers
370374
------------

clang/docs/UsersManual.rst

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,9 +1724,18 @@ floating point semantic models: precise (the default), strict, and fast.
17241724
and ``fast``.
17251725
Details:
17261726

1727-
* ``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.
1728-
* ``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_ACCESS ON`` appeared at the top of the source file.
1729-
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast``
1727+
* ``precise`` Disables optimizations that are not value-safe on
1728+
floating-point data, although FP contraction (FMA) is enabled
1729+
(``-ffp-contract=on``). This is the default behavior. This value resets
1730+
``-fmath-errno`` to its target-dependent default.
1731+
* ``strict`` Enables ``-frounding-math`` and
1732+
``-ffp-exception-behavior=strict``, and disables contractions (FMA). All
1733+
of the ``-ffast-math`` enablements are disabled. Enables
1734+
``STDC FENV_ACCESS``: by default ``FENV_ACCESS`` is disabled. This option
1735+
setting behaves as though ``#pragma STDC FENV_ACCESS ON`` appeared at the
1736+
top of the source file.
1737+
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and
1738+
``ffp-contract=fast``
17301739

17311740
Note: If your command line specifies multiple instances
17321741
of the ``-ffp-model`` option, or if your command line option specifies

clang/include/clang/Basic/FPOptions.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ OPTION(AllowReciprocal, bool, 1, NoSignedZero)
2626
OPTION(AllowApproxFunc, bool, 1, AllowReciprocal)
2727
OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
2828
OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
29-
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
29+
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision)
30+
OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
3031
#undef OPTION

clang/include/clang/Basic/LangOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,7 @@ class FPOptionsOverride {
855855
setNoSignedZeroOverride(!Value);
856856
setAllowReciprocalOverride(!Value);
857857
setAllowApproxFuncOverride(!Value);
858+
setMathErrnoOverride(Value);
858859
if (Value)
859860
/* Precise mode implies fp_contract=on and disables ffast-math */
860861
setAllowFPContractWithinStatement();

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,26 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
23122312
const unsigned BuiltinIDIfNoAsmLabel =
23132313
FD->hasAttr<AsmLabelAttr>() ? 0 : BuiltinID;
23142314

2315+
bool ErrnoOverriden = false;
2316+
// True if math-errno is overriden via the
2317+
// '#pragma float_control(precise, on)'. This pragma disables fast-math,
2318+
// which implies math-errno.
2319+
if (E->hasStoredFPFeatures()) {
2320+
FPOptionsOverride OP = E->getFPFeatures();
2321+
if (OP.hasMathErrnoOverride())
2322+
ErrnoOverriden = OP.getMathErrnoOverride();
2323+
}
2324+
// True if 'atttibute__((optnone)) is used. This attibute overrides
2325+
// fast-math which implies math-errno.
2326+
bool OptNone = CurFuncDecl && CurFuncDecl->hasAttr<OptimizeNoneAttr>();
2327+
2328+
// True if we are compiling at -O2 and errno has been disabled
2329+
// using the '#pragma float_control(precise, off)', and
2330+
// attribute opt-none hasn't been seen.
2331+
bool ErrnoOverridenToFalseWithOpt =
2332+
!ErrnoOverriden && !OptNone &&
2333+
CGM.getCodeGenOpts().OptimizationLevel != 0;
2334+
23152335
// There are LLVM math intrinsics/instructions corresponding to math library
23162336
// functions except the LLVM op will never set errno while the math library
23172337
// might. Also, math builtins have the same semantics as their math library
@@ -2323,9 +2343,38 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
23232343
getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
23242344
bool ConstWithoutExceptions =
23252345
getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID);
2326-
if (FD->hasAttr<ConstAttr>() ||
2327-
((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) &&
2328-
(!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) {
2346+
2347+
// ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is
2348+
// disabled.
2349+
// Math intrinsics are generated only when math-errno is disabled. Any pragmas
2350+
// or attributes that affect math-errno should prevent or allow math
2351+
// intrincs to be generated. Intrinsics are generated:
2352+
// 1- In fast math mode, unless math-errno is overriden
2353+
// via '#pragma float_control(precise, on)', or via an
2354+
// 'attribute__((optnone))'.
2355+
// 2- If math-errno was enabled on command line but overriden
2356+
// to false via '#pragma float_control(precise, off))' and
2357+
// 'attribute__((optnone))' hasn't been used.
2358+
// 3- If we are compiling with optimization and errno has been disabled
2359+
// via '#pragma float_control(precise, off)', and
2360+
// 'attribute__((optnone))' hasn't been used.
2361+
2362+
bool ConstWithoutErrnoOrExceptions =
2363+
ConstWithoutErrnoAndExceptions || ConstWithoutExceptions;
2364+
bool GenerateIntrinsics =
2365+
FD->hasAttr<ConstAttr>() && !ErrnoOverriden && !OptNone;
2366+
if (!GenerateIntrinsics) {
2367+
GenerateIntrinsics =
2368+
ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions;
2369+
if (!GenerateIntrinsics)
2370+
GenerateIntrinsics =
2371+
ConstWithoutErrnoOrExceptions &&
2372+
(!getLangOpts().MathErrno && !ErrnoOverriden && !OptNone);
2373+
if (!GenerateIntrinsics)
2374+
GenerateIntrinsics =
2375+
ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt;
2376+
}
2377+
if (GenerateIntrinsics) {
23292378
switch (BuiltinIDIfNoAsmLabel) {
23302379
case Builtin::BIceil:
23312380
case Builtin::BIceilf:

clang/lib/CodeGen/CGCall.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2279,6 +2279,17 @@ static llvm::FPClassTest getNoFPClassTestMask(const LangOptions &LangOpts) {
22792279
return Mask;
22802280
}
22812281

2282+
void CodeGenModule::AdjustMemoryAttribute(StringRef Name,
2283+
CGCalleeInfo CalleeInfo,
2284+
llvm::AttributeList &Attrs) {
2285+
if (Attrs.getMemoryEffects().getModRef() == llvm::ModRefInfo::NoModRef) {
2286+
Attrs = Attrs.removeFnAttribute(getLLVMContext(), llvm::Attribute::Memory);
2287+
llvm::Attribute MemoryAttr = llvm::Attribute::getWithMemoryEffects(
2288+
getLLVMContext(), llvm::MemoryEffects::writeOnly());
2289+
Attrs = Attrs.addFnAttribute(getLLVMContext(), MemoryAttr);
2290+
}
2291+
}
2292+
22822293
/// Construct the IR attribute list of a function or call.
22832294
///
22842295
/// When adding an attribute, please consider where it should be handled:
@@ -5501,11 +5512,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
55015512
/*AttrOnCallSite=*/true,
55025513
/*IsThunk=*/false);
55035514

5504-
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
5515+
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
55055516
if (FD->hasAttr<StrictFPAttr>())
55065517
// All calls within a strictfp function are marked strictfp
55075518
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::StrictFP);
55085519

5520+
// If -ffast-math is enabled and the function is guarded by an
5521+
// '__attribute__((optnone)) adjust the memory attribute so the BE emits the
5522+
// library call instead of the intrinsic.
5523+
if (FD->hasAttr<OptimizeNoneAttr>() && getLangOpts().FastMath)
5524+
CGM.AdjustMemoryAttribute(CalleePtr->getName(), Callee.getAbstractInfo(),
5525+
Attrs);
5526+
}
55095527
// Add call-site nomerge attribute if exists.
55105528
if (InNoMergeAttributedStmt)
55115529
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoMerge);

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,6 +1260,12 @@ class CodeGenModule : public CodeGenTypeCache {
12601260
llvm::AttributeList &Attrs, unsigned &CallingConv,
12611261
bool AttrOnCallSite, bool IsThunk);
12621262

1263+
/// Adjust Memory attribute to ensure that the BE gets the right attribute
1264+
// in order to generate the library call or the intrinsic for the function
1265+
// name 'Name'.
1266+
void AdjustMemoryAttribute(StringRef Name, CGCalleeInfo CalleeInfo,
1267+
llvm::AttributeList &Attrs);
1268+
12631269
/// Like the overload taking a `Function &`, but intended specifically
12641270
/// for frontends that want to build on Clang's target-configuration logic.
12651271
void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs);

clang/test/CodeGen/math-errno.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// -O2
2+
// RUN: %clang_cc1 -Wno-implicit-function-declaration \
3+
// RUN: -fmath-errno -ffp-contract=on -fno-rounding-math -O2 -emit-llvm -o - %s \
4+
// RUN: | FileCheck %s
5+
6+
// -ffast-math
7+
// RUN: %clang_cc1 -Wno-implicit-function-declaration \
8+
// RUN: -menable-no-infs -menable-no-nans -fapprox-func \
9+
// RUN: -funsafe-math-optimizations -fno-signed-zeros -mreassociate \
10+
// RUN: -freciprocal-math -ffp-contract=fast -fno-rounding-math -ffast-math \
11+
// RUN: -ffinite-math-only -ffast-math -emit-llvm -o - %s \
12+
// RUN: | FileCheck %s -check-prefix=FAST
13+
14+
// -O0
15+
// RUN: %clang_cc1 -Wno-implicit-function-declaration \
16+
// RUN: -fmath-errno -ffp-contract=on -fno-rounding-math -O0 \
17+
// RUN: -emit-llvm -o - %s | FileCheck %s -check-prefix=NOOPT
18+
19+
#pragma float_control(precise,on)
20+
float f1(float x) {
21+
return sqrtf(x);
22+
}
23+
24+
// CHECK-LABEL: define dso_local float @f1
25+
// CHECK: tail call float @sqrtf(float noundef {{.*}}) #[[ATTR4_O2:[0-9]+]]
26+
27+
// FAST-LABEL: define dso_local nofpclass(nan inf) float @f1
28+
// FAST: call fast nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR3_FAST:[0-9]+]]
29+
30+
// NOOPT-LABEL: define dso_local float @f1
31+
// NOOPT: call float @sqrtf(float noundef {{.*}}) #[[ATTR4_NOOPT:[0-9]+]]
32+
33+
#pragma float_control(precise,off)
34+
float f2(float x) {
35+
return sqrtf(x);
36+
}
37+
38+
// CHECK-LABEL: define dso_local float @f2
39+
// CHECK: tail call fast float @llvm.sqrt.f32(float {{.*}})
40+
41+
// FAST-LABEL: define dso_local nofpclass(nan inf) float @f2
42+
// FAST: call fast float @llvm.sqrt.f32(float {{.*}})
43+
44+
// NOOPT-LABEL: define dso_local float @f2
45+
// NOOPT: call float @sqrtf(float {{.*}}) #[[ATTR4_NOOPT:[0-9]+]]
46+
47+
__attribute__((optnone))
48+
float f3(float x) {
49+
x = sqrtf(x);
50+
return x;
51+
}
52+
53+
// CHECK-LABEL: define dso_local float @f3
54+
// CHECK: call float @sqrtf(float noundef {{.*}})
55+
56+
// FAST-LABEL: define dso_local nofpclass(nan inf) float @f3
57+
// FAST: call fast nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR4_FAST:[0-9]+]]
58+
59+
// NOOPT-LABEL: define dso_local float @f3
60+
// NOOPT: call float @sqrtf(float noundef %0) #[[ATTR4_NOOPT:[0-9]+]]
61+
62+
// CHECK: [[ATTR4_O2]] = { nounwind }
63+
// FAST: [[ATTR3_FAST]] = { nounwind willreturn memory(none) }
64+
// NOOPT: [[ATTR4_NOOPT]] = { nounwind }

0 commit comments

Comments
 (0)