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 @@ -529,6 +529,13 @@ unsigned approx_func : 1; }; +inline bool operator==(FPOptions LHS, FPOptions RHS) { + return LHS.getAsOpaqueInt() == RHS.getAsOpaqueInt(); +} +inline bool operator!=(FPOptions LHS, FPOptions RHS) { + return LHS.getAsOpaqueInt() != RHS.getAsOpaqueInt(); +} + /// Describes the kind of translation unit being processed. enum TranslationUnitKind { /// The translation unit is a complete translation unit. diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -215,23 +215,6 @@ (2 * Ctx.getTypeSize(RHSTy)) < PromotedSize; } -static void setBuilderFlagsFromFPFeatures(CGBuilderTy &Builder, - CodeGenFunction &CGF, - FPOptions FPFeatures) { - auto NewRoundingBehavior = FPFeatures.getRoundingMode(); - Builder.setDefaultConstrainedRounding(NewRoundingBehavior); - auto NewExceptionBehavior = - ToConstrainedExceptMD(FPFeatures.getExceptionMode()); - Builder.setDefaultConstrainedExcept(NewExceptionBehavior); - CGF.SetFastMathFlags(FPFeatures); - assert((CGF.CurFuncDecl == nullptr || Builder.getIsFPConstrained() || - isa(CGF.CurFuncDecl) || - isa(CGF.CurFuncDecl) || - (NewExceptionBehavior == llvm::fp::ebIgnore && - NewRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) && - "FPConstrained should be enabled on entire function"); -} - class ScalarExprEmitter : public StmtVisitor { CodeGenFunction &CGF; @@ -764,8 +747,7 @@ if (Ops.LHS->getType()->isFPOrFPVectorTy()) { // Preserve the old values - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, Ops.FPFeatures); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Ops.FPFeatures); return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); } if (Ops.isFixedPointOp()) @@ -2765,9 +2747,8 @@ Value *Zero = llvm::Constant::getNullValue(Oper->getType()); Value *Result; if (Oper->getType()->isFPOrFPVectorTy()) { - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, - E->getFPFeatures(CGF.getLangOpts())); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII( + CGF, E->getFPFeatures(CGF.getLangOpts())); Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp"); } else Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp"); @@ -3179,8 +3160,7 @@ if (Ops.LHS->getType()->isFPOrFPVectorTy()) { llvm::Value *Val; - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, Ops.FPFeatures); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Ops.FPFeatures); Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); if (CGF.getLangOpts().OpenCL && !CGF.CGM.getCodeGenOpts().CorrectlyRoundedDivSqrt) { @@ -3558,8 +3538,7 @@ return EmitOverflowCheckedBinOp(op); if (op.LHS->getType()->isFPOrFPVectorTy()) { - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, op.FPFeatures); // Try to form an fmuladd. if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder)) return FMulAdd; @@ -3746,8 +3725,7 @@ return EmitOverflowCheckedBinOp(op); if (op.LHS->getType()->isFPOrFPVectorTy()) { - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, op.FPFeatures); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, op.FPFeatures); // Try to form an fmuladd. if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) return FMulAdd; @@ -4073,8 +4051,7 @@ if (BOInfo.isFixedPointOp()) { Result = EmitFixedPointBinOp(BOInfo); } else if (LHS->getType()->isFPOrFPVectorTy()) { - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, BOInfo.FPFeatures); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, BOInfo.FPFeatures); if (!IsSignaling) Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp"); else @@ -4227,9 +4204,8 @@ Value *RHS = Visit(E->getRHS()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); if (LHS->getType()->isFPOrFPVectorTy()) { - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, - E->getFPFeatures(CGF.getLangOpts())); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII( + CGF, E->getFPFeatures(CGF.getLangOpts())); LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); } else { @@ -4314,9 +4290,8 @@ Value *RHS = Visit(E->getRHS()); Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType()); if (LHS->getType()->isFPOrFPVectorTy()) { - llvm::IRBuilder<>::FastMathFlagGuard FMFG(Builder); - setBuilderFlagsFromFPFeatures(Builder, CGF, - E->getFPFeatures(CGF.getLangOpts())); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII( + CGF, E->getFPFeatures(CGF.getLangOpts())); LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp"); RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp"); } else { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -704,6 +704,18 @@ return DominatingValue::save(*this, value); } + class CGFPOptionsRAII { + public: + CGFPOptionsRAII(CodeGenFunction &CGF, FPOptions FPFeatures); + ~CGFPOptionsRAII(); + + private: + CodeGenFunction &CGF; + FPOptions OldFPFeatures; + Optional FMFGuard; + }; + FPOptions CurFPFeatures; + public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -65,13 +65,14 @@ : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()), Builder(cgm, cgm.getModule().getContext(), llvm::ConstantFolder(), CGBuilderInserterTy(this)), - SanOpts(CGM.getLangOpts().Sanitize), DebugInfo(CGM.getModuleDebugInfo()), - PGO(cgm), ShouldEmitLifetimeMarkers(shouldEmitLifetimeMarkers( - CGM.getCodeGenOpts(), CGM.getLangOpts())) { + SanOpts(CGM.getLangOpts().Sanitize), CurFPFeatures(CGM.getLangOpts()), + DebugInfo(CGM.getModuleDebugInfo()), PGO(cgm), + ShouldEmitLifetimeMarkers( + shouldEmitLifetimeMarkers(CGM.getCodeGenOpts(), CGM.getLangOpts())) { if (!suppressNewContext) CGM.getCXXABI().getMangleContext().startNewFunction(); - SetFastMathFlags(FPOptions(CGM.getLangOpts())); + SetFastMathFlags(CurFPFeatures); SetFPModel(); } @@ -132,6 +133,51 @@ Builder.setFastMathFlags(FMF); } +CodeGenFunction::CGFPOptionsRAII::CGFPOptionsRAII(CodeGenFunction &CGF, + FPOptions FPFeatures) + : CGF(CGF), OldFPFeatures(CGF.CurFPFeatures) { + CGF.CurFPFeatures = FPFeatures; + + if (OldFPFeatures == FPFeatures) + return; + + FMFGuard.emplace(CGF.Builder); + + auto NewRoundingBehavior = FPFeatures.getRoundingMode(); + CGF.Builder.setDefaultConstrainedRounding(NewRoundingBehavior); + auto NewExceptionBehavior = + ToConstrainedExceptMD(FPFeatures.getExceptionMode()); + CGF.Builder.setDefaultConstrainedExcept(NewExceptionBehavior); + + CGF.SetFastMathFlags(FPFeatures); + + assert((CGF.CurFuncDecl == nullptr || CGF.Builder.getIsFPConstrained() || + isa(CGF.CurFuncDecl) || + isa(CGF.CurFuncDecl) || + (NewExceptionBehavior == llvm::fp::ebIgnore && + NewRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) && + "FPConstrained should be enabled on entire function"); + + auto mergeFnAttrValue = [&](StringRef Name, bool Value) { + auto OldValue = + CGF.CurFn->getFnAttribute(Name).getValueAsString() == "true"; + auto NewValue = OldValue & Value; + if (OldValue != NewValue) + CGF.CurFn->addFnAttr(Name, llvm::toStringRef(NewValue)); + }; + mergeFnAttrValue("no-infs-fp-math", FPFeatures.noHonorInfs()); + mergeFnAttrValue("no-nans-fp-math", FPFeatures.noHonorNaNs()); + mergeFnAttrValue("no-signed-zeros-fp-math", FPFeatures.noSignedZeros()); + mergeFnAttrValue( + "unsafe-fp-math", + FPFeatures.allowAssociativeMath() && FPFeatures.allowReciprocalMath() && + FPFeatures.allowApproximateFunctions() && FPFeatures.noSignedZeros()); +} + +CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() { + CGF.CurFPFeatures = OldFPFeatures; +} + LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; diff --git a/clang/test/CodeGen/fp-function-attrs.cpp b/clang/test/CodeGen/fp-function-attrs.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/fp-function-attrs.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck %s + +float test_default(float a, float b, float c) { + float tmp = a; + tmp += b; + tmp += c; + return tmp; +} + +// CHECK: define float @_Z12test_defaultfff(float %a, float %b, float %c) [[FAST_ATTRS:#[0-9]+]] +// CHECK: fadd fast float {{%.+}}, {{%.+}} +// CHECK: fadd fast float {{%.+}}, {{%.+}} + +float test_precise_on_pragma(float a, float b, float c) { + float tmp = a; + { + #pragma float_control(precise, on) + tmp += b; + } + tmp += c; + return tmp; +} + +// CHECK: define float @_Z22test_precise_on_pragmafff(float %a, float %b, float %c) [[PRECISE_ATTRS:#[0-9]+]] +// CHECK: fadd float {{%.+}}, {{%.+}} +// CHECK: fadd fast float {{%.+}}, {{%.+}} + +float test_reassociate_off_pragma(float a, float b, float c) { + float tmp = a; + { + #pragma clang fp reassociate(off) + tmp += b; + } + tmp += c; + return tmp; +} + +// CHECK: define float @_Z27test_reassociate_off_pragmafff(float %a, float %b, float %c) [[NOREASSOC_ATTRS:#[0-9]+]] +// CHECK: fadd nnan ninf nsz arcp contract afn float {{%.+}}, {{%.+}} +// CHECK: fadd fast float {{%.+}}, {{%.+}} + +// CHECK: attributes [[FAST_ATTRS]] = { {{.*}}"no-infs-fp-math"="true" {{.*}}"no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" {{.*}}"unsafe-fp-math"="true"{{.*}} } +// CHECK: attributes [[PRECISE_ATTRS]] = { {{.*}}"no-infs-fp-math"="false" {{.*}}"no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" {{.*}}"unsafe-fp-math"="false"{{.*}} } +// CHECK: attributes [[NOREASSOC_ATTRS]] = { {{.*}}"no-infs-fp-math"="true" {{.*}}"no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" {{.*}}"unsafe-fp-math"="false"{{.*}} }