diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -4708,7 +4708,12 @@ 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 diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -365,6 +365,10 @@ - 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 ------------ diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -1724,9 +1724,18 @@ 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 diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def --- a/clang/include/clang/Basic/FPOptions.def +++ b/clang/include/clang/Basic/FPOptions.def @@ -26,5 +26,6 @@ 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 diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -855,6 +855,7 @@ setNoSignedZeroOverride(!Value); setAllowReciprocalOverride(!Value); setAllowApproxFuncOverride(!Value); + setMathErrnoOverride(Value); if (Value) /* Precise mode implies fp_contract=on and disables ffast-math */ setAllowFPContractWithinStatement(); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2312,6 +2312,26 @@ const unsigned BuiltinIDIfNoAsmLabel = FD->hasAttr() ? 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(); + + // 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 @@ -2323,9 +2343,38 @@ getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); bool ConstWithoutExceptions = getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID); - if (FD->hasAttr() || - ((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() && !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: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2279,6 +2279,17 @@ 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: @@ -5501,11 +5512,18 @@ /*AttrOnCallSite=*/true, /*IsThunk=*/false); - if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) + if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) { if (FD->hasAttr()) // 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() && 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); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1260,6 +1260,12 @@ 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); diff --git a/clang/test/CodeGen/math-errno.c b/clang/test/CodeGen/math-errno.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/math-errno.c @@ -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 }