Skip to content

Commit

Permalink
Take math-errno into account with '#pragma float_control(precise,on)'…
Browse files Browse the repository at this point in the history
… and

'attribute__((optnone)).

Differential Revision: https://reviews.llvm.org/D151834
  • Loading branch information
zahiraam committed Sep 8, 2023
1 parent 77054f3 commit 2c93e3c
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 9 deletions.
7 changes: 6 additions & 1 deletion clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4708,7 +4708,12 @@ settings can be pushed or popped.
When ``pragma float_control(precise, on)`` is enabled, the section of code
governed by the pragma uses precise floating point semantics, effectively
``-ffast-math`` is disabled and ``-ffp-contract=on``
(fused multiply add) is enabled.
(fused multiply add) is enabled. This pragma enables ``-fmath-errno``.
When ``pragma float_control(precise, off)`` is enabled, unsafe-floating point
optimizations are enabled in the section of code governed by the pragma.
Effectively ``-ffast-math`` is enabled and ``-ffp-contract=fast``. This pragma
disables ``-fmath-errno``.
When ``pragma float_control(except, on)`` is enabled, the section of code
governed by the pragma behaves as though the command-line option
Expand Down
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,10 @@ Floating Point Support in Clang
- Add ``__builtin_elementwise_bitreverse`` builtin for integer types only.
- Add ``__builtin_elementwise_sqrt`` builtin for floating point types only.
- ``__builtin_isfpclass`` builtin now supports vector types.
- ``#pragma float_control(precise,on)`` enables precise floating-point
semantics. If ``math-errno`` is disabled in the current TU, clang will
re-enable ``math-errno`` in the presense of
``#pragma float_control(precise,on)``.

AST Matchers
------------
Expand Down
15 changes: 12 additions & 3 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1724,9 +1724,18 @@ floating point semantic models: precise (the default), strict, and fast.
and ``fast``.
Details:

* ``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_ACCESS ON`` appeared at the top of the source file.
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and ``ffp-contract=fast``
* ``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. This value resets
``-fmath-errno`` to its target-dependent default.
* ``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.
* ``fast`` Behaves identically to specifying both ``-ffast-math`` and
``ffp-contract=fast``

Note: If your command line specifies multiple instances
of the ``-ffp-model`` option, or if your command line option specifies
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/FPOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ OPTION(AllowReciprocal, bool, 1, NoSignedZero)
OPTION(AllowApproxFunc, bool, 1, AllowReciprocal)
OPTION(FPEvalMethod, LangOptions::FPEvalMethodKind, 2, AllowApproxFunc)
OPTION(Float16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, FPEvalMethod)
OPTION(BFloat16ExcessPrecision, LangOptions::ExcessPrecisionKind, 2, Float16ExcessPrecision)
OPTION(MathErrno, bool, 1, BFloat16ExcessPrecision)
#undef OPTION
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,7 @@ class FPOptionsOverride {
setNoSignedZeroOverride(!Value);
setAllowReciprocalOverride(!Value);
setAllowApproxFuncOverride(!Value);
setMathErrnoOverride(Value);
if (Value)
/* Precise mode implies fp_contract=on and disables ffast-math */
setAllowFPContractWithinStatement();
Expand Down
55 changes: 52 additions & 3 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2312,6 +2312,26 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const unsigned BuiltinIDIfNoAsmLabel =
FD->hasAttr<AsmLabelAttr>() ? 0 : BuiltinID;

bool ErrnoOverriden = false;
// True if math-errno is overriden via the
// '#pragma float_control(precise, on)'. This pragma disables fast-math,
// which implies math-errno.
if (E->hasStoredFPFeatures()) {
FPOptionsOverride OP = E->getFPFeatures();
if (OP.hasMathErrnoOverride())
ErrnoOverriden = OP.getMathErrnoOverride();
}
// True if 'atttibute__((optnone)) is used. This attibute overrides
// fast-math which implies math-errno.
bool OptNone = CurFuncDecl && CurFuncDecl->hasAttr<OptimizeNoneAttr>();

// True if we are compiling at -O2 and errno has been disabled
// using the '#pragma float_control(precise, off)', and
// attribute opt-none hasn't been seen.
bool ErrnoOverridenToFalseWithOpt =
!ErrnoOverriden && !OptNone &&
CGM.getCodeGenOpts().OptimizationLevel != 0;

// There are LLVM math intrinsics/instructions corresponding to math library
// functions except the LLVM op will never set errno while the math library
// might. Also, math builtins have the same semantics as their math library
Expand All @@ -2323,9 +2343,38 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
bool ConstWithoutExceptions =
getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID);
if (FD->hasAttr<ConstAttr>() ||
((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) &&
(!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) {

// ConstAttr is enabled in fast-math mode. In fast-math mode, math-errno is
// disabled.
// Math intrinsics are generated only when math-errno is disabled. Any pragmas
// or attributes that affect math-errno should prevent or allow math
// intrincs to be generated. Intrinsics are generated:
// 1- In fast math mode, unless math-errno is overriden
// via '#pragma float_control(precise, on)', or via an
// 'attribute__((optnone))'.
// 2- If math-errno was enabled on command line but overriden
// to false via '#pragma float_control(precise, off))' and
// 'attribute__((optnone))' hasn't been used.
// 3- If we are compiling with optimization and errno has been disabled
// via '#pragma float_control(precise, off)', and
// 'attribute__((optnone))' hasn't been used.

bool ConstWithoutErrnoOrExceptions =
ConstWithoutErrnoAndExceptions || ConstWithoutExceptions;
bool GenerateIntrinsics =
FD->hasAttr<ConstAttr>() && !ErrnoOverriden && !OptNone;
if (!GenerateIntrinsics) {
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions && !ConstWithoutErrnoAndExceptions;
if (!GenerateIntrinsics)
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions &&
(!getLangOpts().MathErrno && !ErrnoOverriden && !OptNone);
if (!GenerateIntrinsics)
GenerateIntrinsics =
ConstWithoutErrnoOrExceptions && ErrnoOverridenToFalseWithOpt;
}
if (GenerateIntrinsics) {
switch (BuiltinIDIfNoAsmLabel) {
case Builtin::BIceil:
case Builtin::BIceilf:
Expand Down
20 changes: 19 additions & 1 deletion clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2279,6 +2279,17 @@ static llvm::FPClassTest getNoFPClassTestMask(const LangOptions &LangOpts) {
return Mask;
}

void CodeGenModule::AdjustMemoryAttribute(StringRef Name,
CGCalleeInfo CalleeInfo,
llvm::AttributeList &Attrs) {
if (Attrs.getMemoryEffects().getModRef() == llvm::ModRefInfo::NoModRef) {
Attrs = Attrs.removeFnAttribute(getLLVMContext(), llvm::Attribute::Memory);
llvm::Attribute MemoryAttr = llvm::Attribute::getWithMemoryEffects(
getLLVMContext(), llvm::MemoryEffects::writeOnly());
Attrs = Attrs.addFnAttribute(getLLVMContext(), MemoryAttr);
}
}

/// Construct the IR attribute list of a function or call.
///
/// When adding an attribute, please consider where it should be handled:
Expand Down Expand Up @@ -5501,11 +5512,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
/*AttrOnCallSite=*/true,
/*IsThunk=*/false);

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

// If -ffast-math is enabled and the function is guarded by an
// '__attribute__((optnone)) adjust the memory attribute so the BE emits the
// library call instead of the intrinsic.
if (FD->hasAttr<OptimizeNoneAttr>() && getLangOpts().FastMath)
CGM.AdjustMemoryAttribute(CalleePtr->getName(), Callee.getAbstractInfo(),
Attrs);
}
// Add call-site nomerge attribute if exists.
if (InNoMergeAttributedStmt)
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoMerge);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,12 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::AttributeList &Attrs, unsigned &CallingConv,
bool AttrOnCallSite, bool IsThunk);

/// Adjust Memory attribute to ensure that the BE gets the right attribute
// in order to generate the library call or the intrinsic for the function
// name 'Name'.
void AdjustMemoryAttribute(StringRef Name, CGCalleeInfo CalleeInfo,
llvm::AttributeList &Attrs);

/// Like the overload taking a `Function &`, but intended specifically
/// for frontends that want to build on Clang's target-configuration logic.
void addDefaultFunctionDefinitionAttributes(llvm::AttrBuilder &attrs);
Expand Down
64 changes: 64 additions & 0 deletions clang/test/CodeGen/math-errno.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// -O2
// RUN: %clang_cc1 -Wno-implicit-function-declaration \
// RUN: -fmath-errno -ffp-contract=on -fno-rounding-math -O2 -emit-llvm -o - %s \
// RUN: | FileCheck %s

// -ffast-math
// RUN: %clang_cc1 -Wno-implicit-function-declaration \
// RUN: -menable-no-infs -menable-no-nans -fapprox-func \
// RUN: -funsafe-math-optimizations -fno-signed-zeros -mreassociate \
// RUN: -freciprocal-math -ffp-contract=fast -fno-rounding-math -ffast-math \
// RUN: -ffinite-math-only -ffast-math -emit-llvm -o - %s \
// RUN: | FileCheck %s -check-prefix=FAST

// -O0
// RUN: %clang_cc1 -Wno-implicit-function-declaration \
// RUN: -fmath-errno -ffp-contract=on -fno-rounding-math -O0 \
// RUN: -emit-llvm -o - %s | FileCheck %s -check-prefix=NOOPT

#pragma float_control(precise,on)
float f1(float x) {
return sqrtf(x);
}

// CHECK-LABEL: define dso_local float @f1
// CHECK: tail call float @sqrtf(float noundef {{.*}}) #[[ATTR4_O2:[0-9]+]]

// FAST-LABEL: define dso_local nofpclass(nan inf) float @f1
// FAST: call fast nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR3_FAST:[0-9]+]]

// NOOPT-LABEL: define dso_local float @f1
// NOOPT: call float @sqrtf(float noundef {{.*}}) #[[ATTR4_NOOPT:[0-9]+]]

#pragma float_control(precise,off)
float f2(float x) {
return sqrtf(x);
}

// CHECK-LABEL: define dso_local float @f2
// CHECK: tail call fast float @llvm.sqrt.f32(float {{.*}})

// FAST-LABEL: define dso_local nofpclass(nan inf) float @f2
// FAST: call fast float @llvm.sqrt.f32(float {{.*}})

// NOOPT-LABEL: define dso_local float @f2
// NOOPT: call float @sqrtf(float {{.*}}) #[[ATTR4_NOOPT:[0-9]+]]

__attribute__((optnone))
float f3(float x) {
x = sqrtf(x);
return x;
}

// CHECK-LABEL: define dso_local float @f3
// CHECK: call float @sqrtf(float noundef {{.*}})

// FAST-LABEL: define dso_local nofpclass(nan inf) float @f3
// FAST: call fast nofpclass(nan inf) float @sqrtf(float noundef nofpclass(nan inf) {{.*}}) #[[ATTR4_FAST:[0-9]+]]

// NOOPT-LABEL: define dso_local float @f3
// NOOPT: call float @sqrtf(float noundef %0) #[[ATTR4_NOOPT:[0-9]+]]

// CHECK: [[ATTR4_O2]] = { nounwind }
// FAST: [[ATTR3_FAST]] = { nounwind willreturn memory(none) }
// NOOPT: [[ATTR4_NOOPT]] = { nounwind }

0 comments on commit 2c93e3c

Please sign in to comment.