aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang/docs/LanguageExtensions.rst7
-rw-r--r--clang/docs/ReleaseNotes.rst4
-rw-r--r--clang/docs/UsersManual.rst15
-rw-r--r--clang/include/clang/Basic/FPOptions.def3
-rw-r--r--clang/include/clang/Basic/LangOptions.h1
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp55
-rw-r--r--clang/lib/CodeGen/CGCall.cpp20
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h6
-rw-r--r--clang/test/CodeGen/math-errno.c64
9 files changed, 166 insertions, 9 deletions
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 3d2e8aa..11cbdca 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -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
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 28a6ec0..19252f0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
------------
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index d047aa3..23b762c 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -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
diff --git a/clang/include/clang/Basic/FPOptions.def b/clang/include/clang/Basic/FPOptions.def
index 4517be6..5b923a1 100644
--- a/clang/include/clang/Basic/FPOptions.def
+++ b/clang/include/clang/Basic/FPOptions.def
@@ -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
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 64fd76b..fb073bf 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -855,6 +855,7 @@ public:
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
index a513eae..5f9199d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -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
@@ -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:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 37de280..e15a463 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -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:
@@ -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);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 79f48b6..073b471 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1260,6 +1260,12 @@ public:
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
index 0000000..aeb30b673
--- /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 }