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 @@ -1765,20 +1765,10 @@ if (!CodeGenOpts.StrictFloatCastOverflow) FuncAttrs.addAttribute("strict-float-cast-overflow", "false"); - // TODO: Are these all needed? - // unsafe/inf/nan/nsz are handled by instruction-level FastMathFlags. - FuncAttrs.addAttribute("no-infs-fp-math", - llvm::toStringRef(LangOpts.NoHonorInfs)); - FuncAttrs.addAttribute("no-nans-fp-math", - llvm::toStringRef(LangOpts.NoHonorNaNs)); - FuncAttrs.addAttribute("unsafe-fp-math", - llvm::toStringRef(LangOpts.UnsafeFPMath)); FuncAttrs.addAttribute("use-soft-float", llvm::toStringRef(CodeGenOpts.SoftFloat)); FuncAttrs.addAttribute("stack-protector-buffer-size", llvm::utostr(CodeGenOpts.SSPBufferSize)); - FuncAttrs.addAttribute("no-signed-zeros-fp-math", - llvm::toStringRef(LangOpts.NoSignedZero)); FuncAttrs.addAttribute( "correctly-rounded-divide-sqrt-fp-math", llvm::toStringRef(CodeGenOpts.CorrectlyRoundedDivSqrt)); 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 @@ -214,23 +214,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; @@ -746,8 +729,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()) @@ -2729,9 +2711,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"); @@ -3143,8 +3124,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) { @@ -3517,8 +3497,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; @@ -3700,8 +3679,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; @@ -4027,8 +4005,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 @@ -4181,9 +4158,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 { @@ -4268,9 +4244,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/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -245,8 +245,18 @@ bool LinkInModules() { for (auto &LM : LinkModules) { if (LM.PropagateAttrs) - for (Function &F : *LM.Module) + for (Function &F : *LM.Module) { Gen->CGM().addDefaultFunctionDefinitionAttributes(F); + auto &LangOpts = Gen->CGM().getLangOpts(); + F.addFnAttr("no-infs-fp-math", + llvm::toStringRef(LangOpts.NoHonorInfs)); + F.addFnAttr("no-nans-fp-math", + llvm::toStringRef(LangOpts.NoHonorNaNs)); + F.addFnAttr("no-signed-zeros-fp-math", + llvm::toStringRef(LangOpts.NoSignedZero)); + F.addFnAttr("unsafe-fp-math", + llvm::toStringRef(LangOpts.UnsafeFPMath)); + } CurLinkModule = LM.Module.get(); 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 @@ -678,6 +678,20 @@ return DominatingValue::save(*this, value); } + class CGFPOptionsRAII : public CGBuilderTy::FastMathFlagGuard { + public: + CGFPOptionsRAII(CodeGenFunction &CGF, FPOptions FPFeatures); + ~CGFPOptionsRAII() = default; + }; + + /// State for the floating point function attributes. At the end of the + /// codegen of a function they will have the strictest configuration required + /// by the statements in the function itself. + bool FnAttrNoInfsFPMath; + bool FnAttrNoNaNsFPMath; + bool FnAttrNoSignedZerosFPMath; + bool FnAttrUnsafeFPMath; + 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 @@ -73,6 +73,11 @@ SetFastMathFlags(FPOptions(CGM.getLangOpts())); SetFPModel(); + + FnAttrNoInfsFPMath = CGM.getLangOpts().NoHonorInfs; + FnAttrNoNaNsFPMath = CGM.getLangOpts().NoHonorNaNs; + FnAttrNoSignedZerosFPMath = CGM.getLangOpts().NoSignedZero; + FnAttrUnsafeFPMath = CGM.getLangOpts().UnsafeFPMath; } CodeGenFunction::~CodeGenFunction() { @@ -132,6 +137,32 @@ Builder.setFastMathFlags(FMF); } +CodeGenFunction::CGFPOptionsRAII::CGFPOptionsRAII(CodeGenFunction &CGF, + FPOptions FPFeatures) + : CGBuilderTy::FastMathFlagGuard(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"); + + CGF.FnAttrNoInfsFPMath &= FPFeatures.noHonorInfs(); + CGF.FnAttrNoNaNsFPMath &= FPFeatures.noHonorNaNs(); + CGF.FnAttrNoSignedZerosFPMath &= FPFeatures.noSignedZeros(); + CGF.FnAttrUnsafeFPMath &= + FPFeatures.allowAssociativeMath() && FPFeatures.allowReciprocalMath() && + FPFeatures.allowApproximateFunctions() && FPFeatures.noSignedZeros(); +} + LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; @@ -445,6 +476,12 @@ ReturnValue = Address::invalid(); } } + + CurFn->addFnAttr("no-infs-fp-math", llvm::toStringRef(FnAttrNoInfsFPMath)); + CurFn->addFnAttr("no-nans-fp-math", llvm::toStringRef(FnAttrNoNaNsFPMath)); + CurFn->addFnAttr("no-signed-zeros-fp-math", + llvm::toStringRef(FnAttrNoSignedZerosFPMath)); + CurFn->addFnAttr("unsafe-fp-math", llvm::toStringRef(FnAttrUnsafeFPMath)); } /// ShouldInstrumentFunction - Return true if the current function should be 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"{{.*}} }