Index: clang/include/clang/Basic/FPOptions.def =================================================================== --- clang/include/clang/Basic/FPOptions.def +++ 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 Index: clang/include/clang/Basic/LangOptions.h =================================================================== --- clang/include/clang/Basic/LangOptions.h +++ clang/include/clang/Basic/LangOptions.h @@ -854,6 +854,7 @@ setNoSignedZeroOverride(!Value); setAllowReciprocalOverride(!Value); setAllowApproxFuncOverride(!Value); + setMathErrnoOverride(Value); if (Value) /* Precise mode implies fp_contract=on and disables ffast-math */ setAllowFPContractWithinStatement(); Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ clang/lib/CodeGen/CGBuiltin.cpp @@ -2283,6 +2283,19 @@ 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(); + // 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 @@ -2294,9 +2307,32 @@ getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); bool ConstWithoutExceptions = getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID); - if (FD->hasAttr() || + + // 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 pragma + // or attribute 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 GenerateIntrinsics = + FD->hasAttr() && !ErrnoOverriden && !OptNone; + if (!GenerateIntrinsics) + GenerateIntrinsics = + !getLangOpts().MathErrno && !ErrnoOverriden && !OptNone; + if (!GenerateIntrinsics) + GenerateIntrinsics = !ErrnoOverriden && !OptNone && + CGM.getCodeGenOpts().OptimizationLevel != 0; + if (GenerateIntrinsics || ((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) && - (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) { + (!ConstWithoutErrnoAndExceptions || GenerateIntrinsics))) { switch (BuiltinIDIfNoAsmLabel) { case Builtin::BIceil: case Builtin::BIceilf: Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2247,6 +2247,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: @@ -5442,11 +5453,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); Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -1252,6 +1252,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); + /// Adds attributes to F according to our CodeGenOptions and LangOptions, as /// though we had emitted it ourselves. We remove any attributes on F that /// conflict with the attributes we add here. Index: clang/test/CodeGen/math-errno.c =================================================================== --- /dev/null +++ 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 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 }